Lambat ORDER OLEH dengan LIMIT

11

Saya punya pertanyaan ini:

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

Saya senang dengan itu:

"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"

Tetapi ketika saya menambahkan LIMIT, eksekusi membutuhkan lebih dari 2 detik:

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

Menjelaskan:

"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"

Saya pikir ini adalah masalah dengan ORDER BY dan LIMIT. Bagaimana saya bisa memaksa PostgreSQL untuk menggunakan indeks dan melakukan pemesanan di akhir?

Subquery tidak membantu:

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

atau:

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

Jawaban:

12

Dugaan saya adalah ini akan memperbaiki kueri Anda:

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;

Saya ulangi WHEREkondisi sebagai elemen pertama dari ORDER BYklausa - yang secara logis berlebihan, tetapi harus menjaga perencana kueri dari asumsi akan lebih baik memproses baris menurut indeks location_displaycount_index- yang ternyata jauh lebih mahal.

Masalah yang mendasarinya adalah bahwa perencana permintaan jelas salah menilai selektivitas dan / atau biaya WHEREkondisi Anda . Saya hanya bisa berspekulasi mengapa itu terjadi.

Apakah Anda menjalankan autovacuum - yang juga harus berjalan ANALYZEdi meja Anda? Dengan demikian, apakah tabel-statistik Anda terkini? Apa pun efeknya jika Anda menjalankan:

ANALYZE location;

Dan coba lagi?

Bisa juga selektivitas @@operator salah menilai. Saya akan membayangkan bahwa sangat sulit untuk memperkirakan karena alasan yang logis.


Jika kueri saya tidak menyelesaikan masalah, dan umumnya untuk memverifikasi teori yang mendasarinya lakukan salah satu dari dua hal ini:

Yang terakhir kurang mengganggu dan hanya mempengaruhi sesi saat ini. Itu meninggalkan metode bitmap heap scandan bitmap index scanterbuka, yang digunakan oleh rencana yang lebih cepat.
Kemudian jalankan kembali kueri.

BTW: Jika teorinya masuk akal, permintaan Anda (seperti yang Anda miliki sekarang) akan jauh lebih cepat dengan istilah pencarian yang kurang selektif dalam kondisi FTS - bertentangan dengan apa yang Anda harapkan. Cobalah.

Erwin Brandstetter
sumber
1
Kueri berfungsi. Mematikan indexscan juga bisa. ANALYZE tidak berfungsi. Terima kasih banyak atas jawaban yang komprehensif.
ziri
0

Saat menggunakan postgresql LIMIT sesuaikan, rencananya akan optimal untuk hanya mengambil subset baris. Sayangnya itu entah bagaimana membuat pilihan yang salah dalam kasus Anda. Ini bisa jadi karena statistik untuk tabel terlalu lama. Coba perbarui statistik dengan menerbitkan lokasi VACUUM ANALYZE;

Memaksa penggunaan indeks biasanya dilakukan dengan melarang penggunaan pemindaian sekuensial (set enable_seqscan = false). Namun dalam kasus Anda itu tidak melakukan pemindaian berurutan itu hanya beralih ke indeks yang berbeda untuk kueri dengan LIMIT.

Jika analisis tidak membantu, bisakah Anda memberi tahu versi postgresql yang Anda gunakan? Juga berapa banyak baris yang ada di tabel?

Eelke
sumber
Analisis tidak membantu. Tabel ini memiliki sekitar 36.000 baris dan saya menggunakan postgresql 9.1.
ziri