ดัชนีคอมโพสิตยังดีสำหรับการค้นหาในเขตข้อมูลแรกหรือไม่


86

สมมติว่าผมมีตารางที่มีสาขาและA Bฉันจะทำให้คำสั่งปกติA+ ดังนั้นฉันสร้างดัชนีคอมโพสิตในB (A,B)คำสั่งในการค้นหาAจะได้รับการปรับให้เหมาะสมอย่างเต็มที่โดยดัชนีคอมโพสิตหรือไม่

นอกจากนี้ผมสร้างดัชนีในAแต่ Postgres Aยังคงใช้ดัชนีคอมโพสิตสำหรับการค้นหาเท่านั้น หากคำตอบก่อนหน้าเป็นบวกฉันคิดว่ามันไม่สำคัญ แต่ทำไมมันถึงเลือกดัชนีคอมโพสิตตามค่าเริ่มต้นหากมีAดัชนีเดียว


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

@dezso น่าสนใจ ค่าใช้จ่ายสำหรับแต่ละแบบสอบถามอยู่ที่ไหน
Luciano

ค่าสแกนดัชนีบิตแมป: 107.98, 43 ms เวลาดำเนินการ การสแกนดัชนีหนึ่งคอลัมน์: ราคา 8.69, สองคอลัมน์: 43.69 เวลาดำเนินการไม่แตกต่างกันอย่างมีนัยสำคัญ (ความผันผวนมีขนาดใหญ่กว่าความแตกต่างระหว่างสอง)
dezso

@Luciano คุณสามารถแสดงexplain analyzeและข้อความค้นหาได้หรือไม่
Craig Ringer

คำตอบ:


88

มันเป็นอย่างแน่นอน เราพูดคุยกันอย่างละเอียดภายใต้คำถามที่เกี่ยวข้องนี้:

พื้นที่ถูกจัดสรรเป็นทวีคูณMAXALIGNซึ่งโดยทั่วไปคือ 8 ไบต์บนระบบปฏิบัติการ 64 บิตหรือ (พบน้อยกว่ามาก) 4 ไบต์บนระบบปฏิบัติการ 32 บิต pg_controldataหากคุณไม่แน่ใจให้ตรวจสอบ นอกจากนี้ยังขึ้นอยู่กับชนิดข้อมูลของคอลัมน์ที่จัดทำดัชนี (บางประเภทจำเป็นต้องใช้ช่องว่างระหว่างการจัดแนว) และเนื้อหาจริง

โดยทั่วไปดัชนีบนintegerคอลัมน์สองคอลัมน์ (4 ไบต์แต่ละตัว) โดยทั่วไปจะมีขนาดใหญ่เท่ากับดัชนีของดัชนีเพียงคอลัมน์เดียวโดยที่อีก 4 ไบต์จะหายไปจากการจัดตำแหน่งช่องว่างภายใน

ในกรณีเช่นนี้มีจริงๆข้อเสียไม่มีการวางแผนแบบสอบถามจะใช้ดัชนีใน(a,b)- (a)เมื่อเทียบกับดัชนีในเพียง และโดยทั่วไปจะดีกว่าสำหรับหลาย ๆ แบบสอบถามเพื่อใช้ดัชนีเดียวกัน โอกาสที่มัน (หรือบางส่วนของมัน) จะอยู่ในแคช (เร็ว) จะเพิ่มขึ้นเมื่อมีการแชร์

หากคุณยังคงมีดัชนีอยู่(a,b)แล้วมันไม่เหมาะสมที่จะสร้างดัชนีใหม่ในเพียง(a)- เว้นแต่จะมีขนาดเล็กลงอย่างมาก เช่นเดียวกับไม่จริงสำหรับเทียบกับ(b,a) (a)ติดตามลิงค์ในบรรทัดแรกเพื่อดูข้อมูลเพิ่มเติม

มาจากทิศทางตรงข้ามเมื่อคุณต้องการดัชนีเพิ่มเติมเช่นนั้นเปิด(a,b)ให้พิจารณาปล่อยดัชนีที่มีอยู่ใน(a)กรณีที่เป็นไปได้ บ่อยครั้งที่เป็นไปไม่ได้เนื่องจากดัชนีของ PK หรือUNIQUEข้อ จำกัด ตั้งแต่ Postgres 11 คุณอาจหนีด้วยการต่อท้ายbนิยามข้อ จำกัด ที่มีส่วนINCLUDEคำสั่งแทน รายละเอียดในคู่มือ

หรือสร้างดัชนีใหม่(b,a)แทนเพื่อครอบคลุมการสืบค้นbเพิ่มเติม สำหรับเงื่อนไขความเท่าเทียมกันเท่านั้นลำดับของนิพจน์ดัชนีในดัชนี btree ไม่สำคัญ แม้ว่ามันจะเกี่ยวข้องกับเงื่อนไขของช่วง ดู:

มีข้อเสียที่เป็นไปได้ที่จะรวมคอลัมน์เพิ่มเติมในดัชนีแม้ว่าจะใช้พื้นที่เพียงอย่างเดียวเท่านั้น

  • เมื่อใดก็ตามที่มีการอัปเดตคอลัมน์เพิ่มเติมตอนนี้ดัชนีต้องการการอัปเดตเช่นกันซึ่งอาจเพิ่มค่าใช้จ่ายในการเขียนการดำเนินการและสร้างดัชนีขยายตัวมากขึ้น
  • การอัปเดตที่น่าสนใจ (Heap Only Tuple) บนตารางไม่สามารถทำได้ในขณะที่คอลัมน์ดัชนีใด ๆ ที่เกี่ยวข้อง

เพิ่มเติมเกี่ยวกับการปรับปรุง HOT:

วิธีการวัดขนาดวัตถุ:


1
คุณสามารถขยายสิ่งนี้เพื่อบอกว่าถ้าฉันมีดัชนีในคอลัมน์ A และจำเป็นต้องเกิดขึ้นเพื่อเพิ่มดัชนีผสม (A, B) ดัชนี A ควรจะลดลง? หากการใช้ดัชนีใหม่ช่วยเพิ่มประสิทธิภาพแคชและ (A, B) ปรับให้เหมาะสมที่สุด A ก็ดูเหมือนว่าดัชนีเพิ่มเติมเกี่ยวกับ A จะเปลืองพื้นที่และอาจทำให้สิ่งต่าง ๆ ช้าลง
jvans

1
@jvans: โดยทั่วไปจริง - มีข้อยกเว้นที่น่าสังเกตและทางเลือก ฉันเพิ่มย่อหน้าลงในที่อยู่นั้น
Erwin Brandstetter

2

ตามคำถามของคุณคุณมีตารางที่มีเขตข้อมูล A และ B หากแบบสอบถามของคุณคือ:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

เครื่องมือเพิ่มประสิทธิภาพจะเลือกดัชนีคอมโพสิตเพื่อหลีกเลี่ยงการแยกการเข้าถึงแบบสุ่ม!


-4

มันเป็นในกรณีถ้าคุณเพิ่งใช้ครั้งแรกในภาคแสดง

มันจะทำการสแกนถ้าคุณใช้คอลัมน์แรกของคอมโพสิตคีย์และคอลัมน์ที่ไม่ใช่คีย์ของคอมโพสิตคีย์

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

[A, B] คือดัชนีของคุณ [C] - คอลัมน์อื่น

ในการใช้ดัชนีคุณเขียนเป็น:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... เพราะเหตุใดจึงเลือกดัชนีคอมโพสิตตามค่าเริ่มต้นหากดัชนี A เดี่ยวพร้อมใช้งาน

มันจะใช้ดัชนีเฉพาะในกรณีที่มีเพรดิเคตหนึ่งหรือสองอัน [A] หรือ [A], [B] มันจะไม่ใช้มันตามคำสั่ง [B], [A] หรือ [A], [C] เพื่อให้สามารถใช้ดัชนีกับคอลัมน์เพิ่มเติม [C] คุณจะต้องบังคับใช้ดัชนีโดยสั่งให้ภาคแสดงเป็น [A], [B] และ [C]


2
คุณทำอะไรให้สำเร็จด้วยB=B? ฉันคิดว่าคุณไม่ประสบความสำเร็จดังนั้นฉันจึงลงคะแนนให้ขาดหลักฐานใด ๆ ที่นี่ไม่ได้ถูกมองข้ามโดยเครื่องมือเพิ่มประสิทธิภาพ
Jack Douglas

2
B=BมีประสิทธิภาพเหมือนกับB IS NOT NULLที่ดูเหมือนไม่มีเหตุผล ไม่จำเป็นต้องใช้ดัชนี(a,b)อย่างแน่นอน
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.