ในฐานข้อมูล Postgres 9.1 ฉันมีตารางที่table1
มีแถว ~ 1.5M และคอลัมน์label
(ชื่อที่เรียบง่ายเพื่อประโยชน์ของคำถามนี้)
มีดัชนีการทำงานของ Trigram-on lower(unaccent(label))
( unaccent()
ถูกทำให้ไม่เปลี่ยนรูปเพื่ออนุญาตให้ใช้ในดัชนี)
แบบสอบถามต่อไปนี้ค่อนข้างเร็ว:
SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword%')));
count
-------
1
(1 row)
Time: 394,295 ms
แต่แบบสอบถามต่อไปนี้ช้าลง:
SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword and some more%')));
count
-------
1
(1 row)
Time: 1405,749 ms
และการเพิ่มคำอื่น ๆ ก็ช้าลงแม้ว่าการค้นหาจะเข้มงวด
ฉันลองใช้เคล็ดลับง่ายๆในการเรียกใช้เคียวรีย่อยสำหรับคำแรกและจากนั้นเคียวรีที่มีสตริงการค้นหาแบบเต็ม แต่ (เศร้า) ผู้วางแผนเคียวรีเห็นผ่านการเสี้ยวของฉัน:
EXPLAIN ANALYZE
SELECT * FROM (
SELECT id, title, label from table1
WHERE lower(unaccent(label)) like lower(unaccent('%someword%'))
) t1
WHERE lower(unaccent(label)) like lower(unaccent('%someword and some more%'));
บิตแมป Heap สแกนบนตารางที่ 1 (ราคา = 16216.01..16220.04 แถว = 1 ความกว้าง = 212) (เวลาจริง = 1824.017..1824.019 แถว = 1 ลูป = 1) ตรวจสอบอีกครั้ง Cond: ((ต่ำกว่า (ไม่ตอบสนอง ((ป้ายกำกับ) :: ข้อความ)) ~~ '% อุกกาบาต%' :: ข้อความ) และ (ต่ำลง (ไม่ตอบกลับ ((ฉลาก) :: ข้อความ)) ~~ '% Gatord และอีกมากมาย % :: ข้อความ)) -> ดัชนีบิตแมปสแกนบน table1_label_hun_gin_trgm (ราคา = 0.00..16216.01 แถว = 1 ความกว้าง = 0) (เวลาจริง = 1823.900..1823.900 แถว = 1 ลูป = 1) ดัชนี Cond: ((ต่ำกว่า (ไม่ถูกต้อง ((ป้ายกำกับ) :: ข้อความ)) ~~ '% Bernardord%' :: ข้อความ) และ (ต่ำกว่า (ไม่ถูกต้อง ((ป้ายกำกับ) :: ข้อความ)) ~~ '% Gatord และอีกมากมาย % :: ข้อความ)) รันไทม์ทั้งหมด: 1824.064 ms
ปัญหาสุดท้ายของฉันคือสตริงการค้นหามาจากเว็บอินเตอร์เฟสซึ่งอาจส่งสตริงค่อนข้างยาวและช้ามากและอาจเป็นเวกเตอร์ DOS
ดังนั้นคำถามของฉันคือ:
- จะเพิ่มความเร็วการสืบค้นได้อย่างไร?
- มีวิธีการแบ่งย่อยเป็นแบบสอบถามย่อยเพื่อให้เร็วขึ้นหรือไม่
- อาจเป็นรุ่นที่ใหม่กว่าของ Postgres ดีกว่า (ฉันลอง 9.4 และดูเหมือนว่าจะไม่เร็วกว่า: ยังคงมีผลเหมือนเดิมบางทีอาจเป็นรุ่นต่อมาหรือไม่)
- อาจจำเป็นต้องใช้กลยุทธ์การจัดทำดัชนีที่แตกต่างกันอย่างไร
unaccent
ไม่เปลี่ยนรูป ฉันเพิ่มสิ่งนี้ในคำถาม
unaccent
โมดูล หนึ่งในเหตุผลที่ฉันแนะนำตัวห่อหุ้มฟังก์ชั่นแทน
unaccent()
ยังมีให้โดยโมดูลเพิ่มเติมและ Postgres ไม่ได้IMMUTABLE
สนับสนุนการจัดทำดัชนีในการทำงานโดยเริ่มต้นตั้งแต่ยังไม่ คุณต้องแก้ไขบางสิ่งและคุณควรพูดถึงสิ่งที่คุณทำในคำถามของคุณ คำแนะนำในการยืนอยู่ของฉัน: stackoverflow.com/a/11007216/939860 นอกจากนี้ดัชนี trigram ยังสนับสนุนการจับคู่แบบตรงตามตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก คุณสามารถลดความซับซ้อนของ:WHERE f_unaccent(label) ILIKE f_unaccent('%someword%')
- ด้วยดัชนีที่ตรงกัน รายละเอียด: stackoverflow.com/a/28636000/939860