ช้าสั่งซื้อด้วย LIMIT


11

ฉันมีคำถามนี้:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

ฉันมีความสุขกับมัน:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

แต่เมื่อฉันเพิ่ม LIMIT การดำเนินการใช้เวลามากกว่า 2 วินาที:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

อธิบาย:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

ฉันคิดว่าเป็นปัญหาของ ORDER BY และ LIMIT ฉันจะบังคับให้ PostgreSQL ใช้ดัชนีและทำการสั่งซื้อในตอนท้ายได้อย่างไร

แบบสอบถามย่อยไม่ได้ช่วย:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

หรือ:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;

คำตอบ:


12

ฉันเดาว่านี่จะแก้ไขคำถามของคุณ:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

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

ปัญหาพื้นฐานคือการวางแผนแบบสอบถามอย่างเห็นได้ชัดผิดการเลือกและ / หรือค่าใช้จ่ายของWHEREเงื่อนไขของคุณอย่างเห็นได้ชัด ฉันเดาได้แค่ว่าทำไม

คุณมีautovacuum ที่ทำงาน - ซึ่งควรดูแลการทำงานANALYZEบนตารางของคุณ? ดังนั้นตารางสถิติของคุณเป็นข้อมูลล่าสุดหรือไม่ ผลกระทบใด ๆ หากคุณเรียกใช้:

ANALYZE location;

ลองอีกครั้งเหรอ?

นอกจากนี้ยังอาจเป็นไปได้ว่าการเลือกสรรของ@@ผู้ปฏิบัติงานถูกตัดสินผิด ฉันคิดว่ามันยากมากที่จะประมาณด้วยเหตุผลเชิงตรรกะ


หากคำถามของฉันไม่ควรแก้ปัญหาและโดยทั่วไปเพื่อตรวจสอบทฤษฎีพื้นฐานทำหนึ่งในสองสิ่งต่อไปนี้ :

หลังมีลักษณะล่วงล้ำน้อยกว่าและมีผลกับเซสชันปัจจุบันเท่านั้น มันออกจากวิธีการbitmap heap scanและbitmap index scanเปิดซึ่งถูกใช้โดยแผนที่เร็วกว่า
จากนั้นเรียกใช้แบบสอบถามอีกครั้ง

BTW: หากทฤษฎีฟังดูแล้วการสืบค้นของคุณ (ตามที่คุณมีตอนนี้) จะเร็วขึ้นมากโดยใช้คำค้นหาที่เลือกน้อยกว่าในสภาพ FTS - ตรงกันข้ามกับสิ่งที่คุณคาดหวัง ลองมัน.


1
แบบสอบถามใช้งานได้ การปิดการจัดทำดัชนีสแกนก็ทำงานได้เช่นกัน วิเคราะห์ไม่ทำงาน ขอบคุณมากสำหรับคำตอบที่ครอบคลุม
ziri

0

เมื่อใช้การปรับ postgresql LIMIT จะต้องมีการวางแผนที่ดีที่สุดสำหรับการเรียกใช้ชุดย่อยของแถวเท่านั้น โชคไม่ดีที่มันเป็นทางเลือกที่ผิดในกรณีของคุณ อาจเป็นเพราะสถิติของตารางนั้นเก่าเกินไป ลองอัปเดตสถิติโดยออก VACUUM ANALYZE location

การบังคับใช้ดัชนีโดยปกติแล้วจะกระทำโดยไม่อนุญาตให้ใช้การสแกนตามลำดับ (ตั้งค่า enable_seqscan = false) อย่างไรก็ตามในกรณีของคุณมันไม่ได้ทำการสแกนตามลำดับเพียงแค่สลับไปที่ดัชนีอื่นสำหรับเคียวรีด้วย LIMIT

ในกรณีที่การวิเคราะห์ไม่สามารถช่วยคุณบอกรุ่นของ postgresql ที่คุณใช้อยู่ มีกี่แถวในตาราง?


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