Trong cơ sở dữ liệu Postgres 9.1, tôi có một bảng table1
có ~ 1,5 triệu hàng và một cột label
(tên đơn giản cho mục đích của câu hỏi này).
Có một chỉ số trigram chức năng trên lower(unaccent(label))
( unaccent()
đã được thực hiện bất biến để cho phép sử dụng nó trong chỉ mục).
Truy vấn sau đây khá nhanh:
SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword%')));
count
-------
1
(1 row)
Time: 394,295 ms
Nhưng truy vấn sau chậm hơn:
SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword and some more%')));
count
-------
1
(1 row)
Time: 1405,749 ms
Và thêm nhiều từ thậm chí còn chậm hơn, mặc dù tìm kiếm chặt chẽ hơn.
Tôi đã thử một mẹo đơn giản để chạy một truy vấn con cho từ đầu tiên và sau đó là một truy vấn với chuỗi tìm kiếm đầy đủ, nhưng (đáng buồn thay) trình hoạch định truy vấn đã thấy qua các mưu mô của tôi:
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%'));
Bitmap Heap Scan trên bảng1 (chi phí = 16216,01..16220.04 hàng = 1 width = 212) (thời gian thực tế = 1824.017..1824.019 hàng = 1 vòng = 1) Kiểm tra lại Cond: ((thấp hơn (không có dấu ((nhãn) :: văn bản)) ~ ~ '% Somethingord%' :: văn bản) VÀ (thấp hơn (không có dấu ((nhãn) :: văn bản)) ~ ~ '% Somethingord và một số chi tiết khác %'::bản văn)) -> Quét chỉ mục Bitmap trên bảng1_label_hun_gin_trgm (chi phí = 0,00..16216,01 hàng = 1 width = 0) (thời gian thực tế = 1823.900..1823.900 hàng = 1 vòng = 1) Chỉ mục Cond: ((thấp hơn (không có dấu ( %'::bản văn)) Tổng thời gian chạy: 1824.064 ms
Vấn đề cuối cùng của tôi là chuỗi tìm kiếm đến từ một giao diện web có thể gửi các chuỗi khá dài và do đó khá chậm và cũng có thể tạo thành một vectơ DOS.
Vì vậy, câu hỏi của tôi là:
- Làm thế nào để tăng tốc độ truy vấn?
- Có cách nào để chia nó thành các truy vấn con để nó nhanh hơn không?
- Có lẽ một phiên bản sau của Postgres là tốt hơn? (Tôi đã thử 9,4 và có vẻ không nhanh hơn: vẫn có hiệu ứng tương tự. Có lẽ là phiên bản mới hơn?)
- Có lẽ một chiến lược lập chỉ mục khác nhau là cần thiết?
unaccent
bất biến. Tôi đã thêm điều này vào câu hỏi.
unaccent
mô-đun. Thay vào đó, một trong những lý do tại sao tôi đề xuất một trình bao bọc hàm.
unaccent()
cũng được cung cấp bởi một mô-đun bổ sung và Postgres không hỗ trợ các chỉ mục trên chức năng theo mặc định vì nó không phải làIMMUTABLE
. Bạn phải thay đổi một cái gì đó và bạn nên đề cập đến những gì bạn đã làm chính xác trong câu hỏi của bạn. Lời khuyên thường trực của tôi: stackoverflow.com/a/11007216/939860 . Ngoài ra, các chỉ số trigram hỗ trợ khớp không phân biệt chữ hoa chữ thường. Bạn có thể đơn giản hóa để:WHERE f_unaccent(label) ILIKE f_unaccent('%someword%')
- với một chỉ mục phù hợp. Chi tiết: stackoverflow.com/a/28636000/939860 .