Seq Scan ที่ไม่คาดคิดเมื่อทำเคียวรีกับบูลีนที่มีค่า NULL


10

ฉันมีคอลัมน์ฐานข้อมูลที่เรียกว่าที่คอลัมน์ชนิดคือauto_review booleanมีดัชนีสำหรับฟิลด์นั้นซึ่งสร้างโดยใช้ ActiveRecord ORM

CREATE INDEX index_table_on_auto_renew ON table USING btree (auto_renew);

เมื่อฉันสอบถามฟิลด์สำหรับค่าบูลีน PG จะใช้ดัชนีตามที่คาดไว้

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" = 'f'
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Bitmap Heap Scan on table  (cost=51.65..826.50 rows=28039 width=186)
   Filter: (NOT auto_renew)
   ->  Bitmap Index Scan on index_domains_on_auto_renew  (cost=0.00..44.64 rows=2185 width=0)
         Index Cond: (auto_renew = false)
(4 rows)

เมื่อมีค่าจะNULLใช้การสแกนตามลำดับ

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" IS NULL
                           QUERY PLAN
----------------------------------------------------------------
 Seq Scan on table  (cost=0.00..1094.01 rows=25854 width=186)
   Filter: (auto_renew IS NULL)
(2 rows)

ฉันอยากรู้เหตุผลที่อยู่เบื้องหลังตัวเลือกนี้

คำตอบ:


19

โดยทั่วไปcol IS NULLเป็นตัวเลือกที่เป็นไปได้สำหรับการค้นหาดัชนี b-tree (ค่าเริ่มต้น) คู่มือ :

นอกจากนี้ยังสามารถใช้เงื่อนไขIS NULLหรือIS NOT NULLเงื่อนไขในคอลัมน์ดัชนีกับดัชนีต้นไม้ B

หากต้องการรับหลักฐานให้ปิดใช้งานการสแกนตามลำดับ (ในเซสชันทดสอบเท่านั้น!):

SET enable_seqscan = OFF;

ฉันพูดคู่มือที่นี่ :

enable_seqscan (boolean)

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

จากนั้นลองอีกครั้ง:

EXPLAIN ANALYZE SELECT * FROM tbl WHERE auto_renew IS NULL;

ซึ่งอาจส่งผลให้การสแกนดัชนีบิตแมปที่ช้ากว่าการสแกนตามลำดับบนตาราง

รีเซ็ตหรือปิดเซสชัน (การตั้งค่าเป็นเซสชันโลคัล)

RESET enable_seqscan;

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

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

หากคุณมีคิวรีจำนวนมากที่มองหาแถวที่มีauto_renew IS NULLและตัวNULLพิมพ์เล็กมาก (และ / หรือคุณต้องการลำดับการเรียง) ดัชนีนี้จะช่วยในการค้นหา / เรียงแถวเหล่านี้อย่างรวดเร็ว:

CREATE INDEX index_tbl_tbl_id_auto_renew_null ON tbl (tbl_id)
WHERE auto_renew IS NULL;

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

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

นอกเหนือ: ORMs เป็น crutches ที่ล้มเหลวอย่างสม่ำเสมอเพื่อให้ได้ประสิทธิภาพสูงสุดจาก RDBMS ของคุณ


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