ดัชนีหลายคอลัมน์และประสิทธิภาพ


31

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

สถานการณ์:

  • PostgreSQL 8.4 ตารางที่มีประมาณหนึ่งล้านแถว

  • ค่าในคอลัมน์c1สามารถมีประมาณ100 ค่าที่แตกต่างกัน เราสามารถสันนิษฐานได้ว่าค่ามีการกระจายอย่างเท่าเทียมกันดังนั้นเราจึงมีประมาณ 10,000 แถวสำหรับทุกค่าที่เป็นไปได้

  • คอลัมน์c2สามารถมี1,000 ค่าที่แตกต่าง เรามี 1,000 แถวสำหรับทุกค่าที่เป็นไปได้

เมื่อค้นหาข้อมูลเงื่อนไขจะมีค่าสำหรับคอลัมน์สองคอลัมน์เหล่านี้เสมอดังนั้นตารางจะมีดัชนีหลายคอลัมน์ซึ่งรวม c1 และ c2 ฉันได้อ่านเกี่ยวกับความสำคัญของการจัดเรียงคอลัมน์ในดัชนีหลายคอลัมน์อย่างถูกต้องหากคุณมีข้อความค้นหาที่ใช้เพียงคอลัมน์เดียวในการกรอง นี่ไม่ใช่กรณีในสถานการณ์ของเรา

คำถามของฉันคือคำถามนี้:

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

ป้อนคำอธิบายรูปภาพที่นี่

ภาพที่นำมาจากบทความที่อ้างอิงเกี่ยวกับดัชนีหลายคอลัมน์

แบบสอบถามใช้ค่าจากสองคอลัมน์ในการกรอง ฉันไม่มีข้อความค้นหาที่ใช้เพียงหนึ่งคอลัมน์ในการกรอง พวกเขาทั้งหมดคือ: WHERE c1=@ParameterA AND c2=@ParameterB. นอกจากนี้ยังมีเงื่อนไขเช่นนี้:WHERE c1 = "abc" AND c2 LIKE "ab%"

คำตอบ:


36

ตอบ

เมื่อคุณอ้างถึงเว็บไซต์use-the-index-luke.comให้พิจารณาบท:

ใช้ดัชนีลุค› ประโยคที่› การค้นหาช่วง› Greater, Less and BETWEEN

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

Rule of thumb: index for equality first  then for ranges.

ยังดีสำหรับคอลัมน์เดียวหรือไม่

สิ่งที่ต้องทำสำหรับเคียวรีในคอลัมน์เดียวดูเหมือนจะชัดเจน รายละเอียดเพิ่มเติมและมาตรฐานที่เกี่ยวข้องกับคำถามที่เกี่ยวข้องเหล่านี้:

คอลัมน์ที่เลือกน้อยลงก่อน?

นอกจากนั้นแล้วถ้าคุณมีเงื่อนไขความเสมอภาคสำหรับทั้งสองคอลัมน์ล่ะ

ชั่งหัวมัน ใส่คอลัมน์แรกที่มีแนวโน้มที่จะได้รับเงื่อนไขของตัวเองมากกว่าซึ่งสำคัญจริงๆ

พิจารณาตัวอย่างนี้หรือทำซ้ำด้วยตัวคุณเอง ฉันสร้างตารางง่ายๆสองคอลัมน์ที่มีแถว 100k หนึ่งที่มีน้อยมากอีกอันหนึ่งมีค่าแตกต่างกันมากมาย :

CREATE TEMP TABLE t AS
SELECT (random() * 10000)::int AS lots
     , (random() * 4)::int     AS few
FROM generate_series (1, 100000);

DELETE FROM t WHERE random() > 0.9;  -- create some dead tuples, more "real-life"

ANALYZE t;

SELECT count(distinct lots)   -- 9999
     , count(distinct few)    --    5
FROM   t;

ค้นหา:

SELECT *
FROM   t
WHERE  lots = 2345
AND    few = 2;

EXPLAIN ANALYZE เอาท์พุท (ดีที่สุด 10 เพื่อไม่รวมเอฟเฟ็กต์แคช):

Seq สแกนบน t (ราคา = 0.00..5840.84 แถว = 2 ความกว้าง = 8)
               (เวลาจริง = 5.646 ..15.535 แถว = 2 ลูป = 1)
  ตัวกรอง: ((มาก = 2345) และ (น้อย = 2))
  Buffers: local hit = 443
รันไทม์ทั้งหมด: 15.557 ms

เพิ่มดัชนีทดสอบซ้ำ:

CREATE INDEX t_lf_idx ON t(lots, few);
การสแกนดัชนีโดยใช้ t_lf_idx บน t (ราคา = 0.00..3.76 แถว = 2 ความกว้าง = 8)
                                (เวลาจริง = 0.008..0.011 แถว = 2 ลูป = 1)
  ดัชนี Cond: ((ล็อต = 2345) และ (น้อย = 2))
  บัฟเฟอร์: local hit = 4
รันไทม์ทั้งหมด: 0.027 ms

เพิ่มดัชนีอื่นทดสอบอีกครั้ง:

DROP INDEX t_lf_idx;
CREATE INDEX t_fl_idx  ON t(few, lots);
การสแกนดัชนีโดยใช้ t_fl_idx บน t (ราคา = 0.00..3.74 แถว = 2 ความกว้าง = 8)
                                (เวลาจริง = 0.007..0.011 แถว = 2 ลูป = 1)
  ดัชนี Cond: ((น้อย = 2) AND (มากมาย = 2345))
  บัฟเฟอร์: local hit = 4
รันไทม์ทั้งหมด: 0.027 ms

นี่เป็นกรณีของคอลัมน์ 3 (หรือมากกว่า) ในดัชนีหรือไม่
hayd

@hayd: ไม่แน่ใจว่าคำว่า "นี่" หมายถึงอะไร คุณอาจจะถามคำถามใหม่ คุณสามารถอ้างอิงอันนี้สำหรับบริบทได้เสมอ (และแสดงความคิดเห็นที่นี่เพื่อลิงค์กลับ)
Erwin Brandstetter

โดย "นี้" ผมหมายความว่า "ไม่สั่งซื้อของเรื่องนิยามดัชนีถ้ามีมากกว่า 2 คอลัมน์ในความหมายดัชนี"
hayd

@hayd: จุดที่สำคัญที่สุด: ดัชนี btree ดีสำหรับคำสั่งที่มีเงื่อนไขความเท่าเทียมกันในการแสดงดัชนีนำหน้า การสั่งซื้อในหมู่ผู้ที่ไม่เกี่ยวข้องส่วนใหญ่ รายละเอียดอื่น ๆ อีกมากมายที่ไม่เหมาะสมกับความคิดเห็น ...
Erwin Brandstetter

ขอบคุณฉันจะลองและเขียนคำถามที่เชื่อมโยงกันและเชื่อมโยงกับมัน
hayd

11

ถ้าอย่างที่คุณพูดแบบสอบถามที่เกี่ยวข้องกับ 2 คอลัมน์เหล่านี้คือการตรวจสอบความเท่าเทียมกันของทั้งสองคอลัมน์เช่น:

WHERE c1=@ParameterA AND c2=@ParameterB

ไม่รำคาญกับสิ่งนี้ ฉันสงสัยว่าจะมีความแตกต่างใด ๆ และหากมีอย่างใดอย่างหนึ่งมันจะเล็กน้อย คุณสามารถทดสอบได้แน่นอนด้วยข้อมูลและการตั้งค่าเซิร์ฟเวอร์ของคุณ DBMS รุ่นต่าง ๆ สามารถทำงานแตกต่างกันเล็กน้อยเกี่ยวกับการปรับให้เหมาะสม

ลำดับภายในดัชนีจะมีความสำคัญสำหรับการสืบค้นประเภทอื่น ๆ โดยมีการตรวจสอบคอลัมน์เดียวเท่านั้นหรือเงื่อนไขความไม่เท่าเทียมกันหรือเงื่อนไขในคอลัมน์หนึ่งและการจัดกลุ่มในส่วนอื่น ๆ ฯลฯ

หากฉันต้องเลือกหนึ่งในสองคำสั่งซื้อฉันจะเลือกคอลัมน์ที่เลือกน้อยกว่าก่อน พิจารณาตารางที่มีคอลัมน์และyear monthก็น่าจะเป็นมากกว่าที่คุณจำเป็นต้องมีWHERE year = 2000เงื่อนไขหรือหรือWHERE year BETWEEN 2000 AND 2013WHERE (year, month) BETWEEN (1999, 6) AND (2000, 5)

WHERE month = 7 GROUP BY yearอาจต้องมีการค้นหาชนิดของข้อความ(ค้นหาผู้ที่เกิดในเดือนกรกฎาคม) แต่อาจจะน้อยกว่านี้ แน่นอนว่าขึ้นอยู่กับข้อมูลจริงที่เก็บไว้ในตารางของคุณ เลือกหนึ่งในการสั่งซื้อสำหรับตอนนี้พูดและคุณก็สามารถเพิ่มดัชนีอื่นในภายหลัง(c1, c2)(c2, c1)


อัพเดทหลังจากความคิดเห็นของ OP:

นอกจากนี้ยังมีเงื่อนไขเช่นนี้: WHERE c1 = 'abc' AND c2 LIKE 'ab%'

ประเภทของแบบสอบถามนี้หากเงื่อนไขช่วงในc2คอลัมน์และจะต้องมี(c1, c2)ดัชนี หากคุณมีคิวรีประเภทย้อนกลับ:

WHERE c2 = 'abc' AND c1 LIKE 'ab%'

ถ้าเป็น(c2, c1)เช่นนั้นก็จะดีถ้าคุณมีดัชนีเช่นกัน

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