Saya memiliki tabel yang berisi data yang diekstrak dari dokumen teks. Data disimpan dalam kolom yang disebut "CONTENT"
sebagai tempat saya membuat indeks ini menggunakan GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Saya menggunakan kueri berikut untuk melakukan pencarian teks lengkap di atas meja:
SELECT "ITEMID",
ts_rank(setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C') ,
plainto_tsquery('english', 'searchTerm')) AS "RANK"
FROM "File"
WHERE setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C')
@@ plainto_tsquery('english', 'searchTerm')
ORDER BY "RANK" DESC
LIMIT 5;
Tabel File berisi 250.000 baris dan setiap "CONTENT"
entri terdiri dari satu kata acak dan string teks yang sama untuk semua baris.
Sekarang, ketika saya mencari kata acak (1 hit di seluruh tabel) kueri berjalan sangat cepat (<100 ms). Namun, ketika saya mencari kata yang ada di semua baris, kueri berjalan sangat lambat (10 menit atau lebih).
EXPLAIN ANALYZE
menunjukkan bahwa untuk pencarian 1-hit, Pemindaian Indeks Bitmap diikuti oleh Bitmap Heap Scan dilakukan. Untuk pencarian lambat, pemindaian Seq dilakukan sebagai gantinya, yang memakan waktu begitu lama.
Memang, tidak realistis untuk memiliki data yang sama di semua baris. Tetapi karena saya tidak dapat mengontrol dokumen teks yang diunggah oleh pengguna, atau pencarian yang mereka lakukan, ada kemungkinan skenario serupa muncul (mencari istilah dengan kejadian yang sangat tinggi dalam DB). Bagaimana saya dapat meningkatkan kinerja permintaan pencarian saya untuk skenario seperti itu?
Menjalankan PostgreSQL 9.3.4
Paket kueri dari EXPLAIN ANALYZE
:
Pencarian cepat (1 hit dalam DB)
"Limit (cost=2802.89..2802.90 rows=5 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" -> Sort (cost=2802.89..2806.15 rows=1305 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''wfecg'''::tsquery))"
" Sort Method: quicksort Memory: 25kB"
" -> Bitmap Heap Scan on "File" (cost=38.12..2781.21 rows=1305 width=26) (actual time=0.030..0.031 rows=1 loops=1)"
" Recheck Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
" -> Bitmap Index Scan on "File_contentIndex" (cost=0.00..37.79 rows=1305 width=0) (actual time=0.012..0.012 rows=1 loops=1)"
" Index Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
"Total runtime: 0.069 ms"
Pencarian lambat (250 ribu klik di DB)
"Limit (cost=14876.82..14876.84 rows=5 width=26) (actual time=519667.404..519667.405 rows=5 loops=1)"
" -> Sort (cost=14876.82..15529.37 rows=261017 width=26) (actual time=519667.402..519667.402 rows=5 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''cyberspace'''::tsquery))"
" Sort Method: top-N heapsort Memory: 25kB"
" -> Seq Scan on "File" (cost=0.00..10541.43 rows=261017 width=26) (actual time=2.097..519465.953 rows=261011 loops=1)"
" Filter: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''cyberspace'''::tsquery)"
" Rows Removed by Filter: 6"
"Total runtime: 519667.429 ms"
explain (analyze, buffers)
, lebih disukai dengan track_io_timing diatur ke ON
? Tidak mungkin perlu waktu 520 detik untuk memindai tabel itu, kecuali Anda menyimpannya di RAID floppy disk. Pasti ada sesuatu yang patologis di sana. Juga, untuk apa pengaturan Anda random_page_cost
, dan parameter biaya lainnya?
ORDER BY "RANK" DESC
. Saya akan menyelidikipg_trgm
dengan indeks GiST dan operator kesamaan / jarak sebagai alternatif. Pertimbangkan: dba.stackexchange.com/questions/56224/… . Bahkan mungkin menghasilkan hasil yang "lebih baik" (selain lebih cepat).