Tôi có một bảng chứa dữ liệu được trích xuất từ các tài liệu văn bản. Dữ liệu được lưu trữ trong một cột được gọi "CONTENT"
mà tôi đã tạo chỉ mục này bằng GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Tôi sử dụng truy vấn sau đây để thực hiện tìm kiếm toàn văn bản trên bảng:
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;
Bảng Tệp chứa 250 000 hàng và mỗi "CONTENT"
mục bao gồm một từ ngẫu nhiên và một chuỗi văn bản giống nhau cho tất cả các hàng.
Bây giờ, khi tôi tìm kiếm một từ ngẫu nhiên (1 lần nhấn trong toàn bộ bảng), truy vấn sẽ chạy rất nhanh (<100 ms). Tuy nhiên, khi tôi tìm kiếm một từ có trong tất cả các hàng, truy vấn sẽ chạy rất chậm (10 phút trở lên).
EXPLAIN ANALYZE
cho thấy đối với tìm kiếm 1 lần, Quét chỉ mục Bitmap theo sau là Quét heap Bitmap được thực hiện. Đối với tìm kiếm chậm, Seq Scan được thực hiện thay vào đó là quá trình mất nhiều thời gian.
Cấp, nó không thực tế để có cùng một dữ liệu trong tất cả các hàng. Nhưng vì tôi không thể kiểm soát các tài liệu văn bản được người dùng tải lên, cũng như các tìm kiếm họ thực hiện nên có thể xảy ra một kịch bản tương tự (tìm kiếm theo các thuật ngữ có tỷ lệ xuất hiện rất cao trong DB). Làm cách nào tôi có thể tăng hiệu suất của truy vấn tìm kiếm cho kịch bản như vậy?
Chạy PostgreSQL 9.3.4
Kế hoạch truy vấn từ EXPLAIN ANALYZE
:
Tìm kiếm nhanh (1 lần truy cập trong 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"
Tìm kiếm chậm (250k lượt truy cập trong 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)
, tốt nhất là với track_io_timing được đặt thành ON
không? Không có cách nào phải mất 520 giây để quét seq bảng đó, trừ khi bạn đã lưu nó trên RAID của đĩa mềm. Một cái gì đó chắc chắn là bệnh lý ở đó. Ngoài ra, cài đặt của bạn là gì random_page_cost
và các thông số chi phí khác?
ORDER BY "RANK" DESC
. Tôi sẽ điều trapg_trgm
với chỉ số GiST và các toán tử tương tự / khoảng cách thay thế. Hãy xem xét: dba.stackexchange.com/questions/56224/ . Thậm chí có thể tạo ra kết quả "tốt hơn" (bên cạnh việc nhanh hơn).