สแกนดัชนีช้าในตารางขนาดใหญ่


12

ใช้ PostgreSQL 9.2 ฉันมีปัญหากับการสืบค้นที่ช้าในตารางที่ค่อนข้างใหญ่ (200+ ล้านแถว) ฉันไม่ได้พยายามอะไรที่บ้าคลั่งเพียงแค่เพิ่มคุณค่าทางประวัติศาสตร์ ด้านล่างคือแบบสอบถามและผลลัพธ์แผนแบบสอบถาม

เค้าโครงตารางของฉัน:

                                   Table "public.energy_energyentry"
  Column   |           Type           |                            Modifiers
-----------+--------------------------+-----------------------------------------------------------------
 id        | integer                  | not null default nextval('energy_energyentry_id_seq'::regclass)
 prop_id   | integer                  | not null
 timestamp | timestamp with time zone | not null
 value     | double precision         | not null
Indexes:
    "energy_energyentry_pkey" PRIMARY KEY, btree (id)
    "energy_energyentry_prop_id" btree (prop_id)
    "energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
    "energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED

ข้อมูลมีตั้งแต่ 2012-01-01 จนถึงปัจจุบันด้วยข้อมูลใหม่ที่เพิ่มเข้ามาอย่างต่อเนื่อง มีค่าต่างกันประมาณ 2.2k ในprop_idคีย์ต่างประเทศซึ่งกระจายอย่างเท่าเทียมกัน

ฉันสังเกตเห็นว่าการประมาณแถวไม่ได้อยู่ไกล แต่การประมาณการต้นทุนดูใหญ่กว่าด้วยปัจจัย 4x นี่อาจไม่ใช่ปัญหา แต่มีอะไรที่ฉันทำได้บ้างไหม

ฉันคาดว่าการเข้าถึงดิสก์อาจเป็นปัญหาเนื่องจากตารางไม่ได้อยู่ในหน่วยความจำตลอดเวลา

EXPLAIN ANALYZE 
SELECT SUM("value") 
FROM "energy_energyentry" 
WHERE 
  "prop_id"=82411 
  AND "timestamp">'2014-06-11' 
  AND "timestamp"<'2014-11-11'
;
 Aggregate  (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1)
   ->  Index Scan using energy_energyentry_prop_id_timestamp_idx on  energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1)
         Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone))
 Total runtime: 51504.841 ms

ข้อเสนอแนะวิธีการทำให้เร็วขึ้น?
ฉันก็สบายดีที่เพิ่งได้ยินฉันไม่ได้ทำอะไรแปลก ๆ


1
โปรดบอกเราว่าตารางของคุณมีลักษณะอย่างไรมีดัชนีอะไรบ้างและมีการกระจายข้อมูล
Colin 't Hart

ฉันเพิ่มข้อมูลเพิ่มเติมที่คุณถาม Dunno ไม่ว่าฉันจะพลาดอะไรก็ตาม
Exelian

2
แปลก: อธิบายของคุณวิเคราะห์แสดงให้เห็นว่ายังแสดงให้เห็นถึงความหมายของตารางprop_time_idx entry_prop_id_timestamp_idxนี่คือดัชนีเดียวกันหรือไม่ กรุณาแก้ไข
Colin 't Hart

หากคุณอ้างอิงโดย 'การประมาณการต้นทุนดูเหมือนจะเป็นปัจจัยที่ใหญ่กว่า 4x' เนื่องจากตัวเลขค่าใช้จ่ายนั้นประมาณ 4 เท่าของเวลาจริงโปรดสังเกตว่าทั้งสองไม่มีอะไรเกี่ยวข้องกัน ค่าใช้จ่ายเป็นเพียงการประมาณการซึ่งช่วยให้เครื่องมือเพิ่มประสิทธิภาพการสืบค้นสามารถเลือกแผนการค้นหาที่ดีที่สุด นอกบริบทนี้มันมักจะเป็นค่าที่ไม่มีความหมาย
dezso

1
ช่วงวันที่ของคุณแสดงถึงกี่เปอร์เซ็นต์ของตาราง (โดยไม่คำนึงถึงค่าสำหรับprop) ถ้าเป็นเพียงเปอร์เซนต์เล็ก ๆ บางทีดัชนี("timestamp", prop)อาจจะดีกว่า ดัชนีหลายรายการที่มีคอลัมน์นำเหมือนกัน ( propในกรณีของคุณ) ก็มักจะซ้ำซ้อน
Colin 't Hart

คำตอบ:


10

ตารางของคุณใหญ่และดัชนีใด ๆ ที่ครอบคลุมทั้งตาราง สมมติว่า:

  • timestamp = now()มีการป้อนเฉพาะข้อมูลใหม่ (พร้อม)
  • แถวที่มีอยู่จะไม่เปลี่ยนแปลงหรือลบ
  • คุณมีข้อมูลตั้งแต่ 2012-01-01 แต่ข้อความค้นหาส่วนใหญ่ในปีปัจจุบัน (?)

ฉันขอแนะนำดัชนีบางส่วน (ครอบคลุม!) หลายคอลัมน์ :

CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0';  -- adapt to your needs

รวมเฉพาะช่วงเวลาที่มีการสอบถามอย่างสม่ำเสมอ ประสิทธิผลลดลงเมื่อเวลาผ่านไปด้วยรายการใหม่ สร้างดัชนีใหม่เป็นครั้งคราว (คุณอาจต้องปรับการค้นหาของคุณ) ดูคำตอบที่ลิงก์ด้านล่าง

ค่าคอลัมน์สุดท้ายมีอยู่เฉพาะที่จะได้รับดัชนีเพียงสแกนจากนี้ การตั้งค่า autovacuum ก้าวร้าวอาจช่วยโดยการเก็บรักษาแผนที่มองเห็นได้ถึงวันที่เหมือน @jjanes กล่าวแล้ว

ดัชนีบางส่วนควรพอดีกับ RAM ได้ง่ายขึ้นและอยู่ที่นั่นนานกว่า

คุณอาจต้องรวมWHEREเงื่อนไขนี้ไว้ในแบบสอบถามเพื่อให้ผู้วางแผนเข้าใจว่าดัชนีมีผลกับแบบสอบถามเช่น:

SELECT sum(value) AS sum_value
FROM   energy_energyentry
WHERE  prop_id = 82411 
AND   "timestamp" > '2014-06-11 0:0' 
AND   "timestamp" < '2014-11-11 0:0'
AND   "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed

เนื่องจากข้อความค้นหาของคุณมีการสรุปเป็นจำนวนมากแถว ( rows=13578) จึงอาจต้องใช้เวลาสักพักถึงแม้จะเป็นการสแกนแบบดัชนีเท่านั้น ไม่ควรอยู่ใกล้ 50 วินาที น้อยกว่าหนึ่งวินาทีบนฮาร์ดแวร์ที่เหมาะสมครึ่งทาง

ที่เกี่ยวข้อง(แต่ไม่ต้องสนใจCLUSTERและFILLFACTORทั้งคู่จะไม่เกี่ยวข้องหากคุณสามารถสแกนดัชนีอย่างเดียวจากสิ่งนี้) :

นอกเหนือ:
เนื่องจากขณะนี้คุณมีดัชนีอยู่(prop_id, "timestamp")ดัชนีเพิ่มเติม(prop_id)อาจจะมีค่ามากกว่าที่ควรจะเป็น:


ตอนนี้ Postgres รองรับดัชนี BRIN แล้วจะมีประโยชน์ที่นี่หรือไม่ ฉันวางแผนที่จะเก็บข้อมูลเกี่ยวกับ postgres ประมาณ 140 ล้านแถว BRIN เป็นดัชนีที่เหมาะสมที่จะใช้กับตารางที่มีขนาดใหญ่หรือไม่
Arya

2

หากคุณสร้างดัชนีใน (prop_id, "timestamp", "value") ดังนั้นคุณสามารถใช้การสแกนเฉพาะดัชนีเพื่อคำนวณค่าโดยไม่ต้องไปที่ตาราง สิ่งนี้สามารถบันทึกการเข้าถึงดิสก์แบบสุ่มจำนวนมาก

เพื่อให้ได้ประโยชน์มากที่สุดคุณต้องก้าวร้าวเกี่ยวกับการดูดโต๊ะ การตั้งค่า autovac เริ่มต้นนั้นไม่รุนแรงพอสำหรับตารางแบบแทรกเท่านั้นที่คุณต้องการสนับสนุนการสแกนดัชนีเท่านั้นอย่างมีประสิทธิภาพ


การเพิ่มคุณค่าอาจจะน่าสนใจแน่นอนฉันจะดูว่ามันจะเร่งความเร็วให้เร็วขึ้นหรือไม่ คุณมีคำแนะนำสำหรับการตั้งค่าสูญญากาศหรือเอกสารที่ฉันสามารถดูได้หรือไม่?
Exelian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.