ทำไม PostgreSQL ทำการสแกนตามลำดับในคอลัมน์ที่จัดทำดัชนี


150

ตัวอย่างที่ง่ายมาก - หนึ่งตารางหนึ่งดัชนีหนึ่งแบบสอบถาม:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

ให้ฉัน:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

ทำไมมันไม่ทำการสแกนดัชนีแทน? ฉันพลาดอะไรไป

คำตอบ:


222

หาก SELECT ส่งกลับมากกว่าประมาณ 5-10% ของแถวทั้งหมดในตารางการสแกนตามลำดับจะเร็วกว่าการสแกนดัชนีมาก

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

Btw: สิ่งนี้เป็นจริงสำหรับ DBMS อื่น ๆ เช่นกัน - การเพิ่มประสิทธิภาพบางอย่างเช่น "การสแกนดัชนีเท่านั้น" (แต่สำหรับ SELECT * มันไม่น่าเป็นไปได้อย่างยิ่งที่ DBMS จะไปหา "การสแกนดัชนีเท่านั้น")


12
5-10% นั้นขึ้นอยู่กับการตั้งค่าคอนฟิเกอเรชันและการจัดเก็บข้อมูลเช่นกัน มันไม่ใช่ตัวเลขที่ยากนัก
Frank Heikens

6
@ Frank: นั่นเป็นเหตุผลที่ฉันพูดว่า "โดยประมาณ" :) แต่ขอบคุณที่ชี้ให้เห็น
a_horse_with_no_name

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

4
คำถามที่น่าสนใจคือฐานข้อมูลรู้จำนวนคิวรีที่จะส่งคืนโดยไม่ดำเนินการก่อนหรือไม่ มันเก็บสถิติเช่นจำนวนค่าที่แตกต่างกับขนาดตารางที่ไหนสักแห่งหรือไม่?
Laurent Grégoire

7
@ LaurentGrégoire: ใช่ฐานข้อมูลจะจัดเก็บสถิติเกี่ยวกับจำนวนแถวและการแจกแจงค่า ดูรายละเอียดเพิ่มเติมได้จากคู่มือ: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name


0

ในการสแกนดัชนีอ่านส่วนหัวของการกระโดดจากแถวหนึ่งไปอีกแถวหนึ่งซึ่งช้ากว่า 1000 เท่าเมื่ออ่านบล็อกทางกายภาพถัดไป (ในการสแกนตามลำดับ)

ดังนั้นหาก (จำนวนระเบียนที่จะดึง * 1,000) น้อยกว่าจำนวนระเบียนทั้งหมดการสแกนดัชนีจะทำงานได้ดีขึ้น


0

@a_horse_with_no_name อธิบายมันค่อนข้างดี นอกจากนี้หากคุณต้องการใช้การสแกนดัชนีคุณควรใช้ช่วงที่มีขอบเขตในส่วนคำสั่ง เช่น - ปี> 2019 และปี <2020

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

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