Truy vấn của bạn là khá nhiều tối ưu. Cú pháp sẽ không ngắn hơn nhiều, truy vấn sẽ không nhanh hơn nhiều:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Nếu bạn thực sự muốn rút ngắn cú pháp , hãy sử dụng biểu thức chính quy với các nhánh :
...
WHERE name ~ '^(B|D).*'
Hoặc nhanh hơn một chút, với một lớp nhân vật :
...
WHERE name ~ '^[BD].*'
Một thử nghiệm nhanh mà không có chỉ số mang lại kết quả nhanh hơn so với SIMILAR TO
trong cả hai trường hợp đối với tôi.
Với chỉ số B-Tree thích hợp, LIKE
chiến thắng cuộc đua này bằng các đơn đặt hàng lớn.
Đọc những điều cơ bản về khớp mẫu trong hướng dẫn .
Chỉ số cho hiệu suất vượt trội
Nếu bạn quan tâm đến hiệu suất, hãy tạo một chỉ mục như thế này cho các bảng lớn hơn:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Làm cho loại truy vấn này nhanh hơn theo thứ tự cường độ. Xem xét đặc biệt áp dụng cho thứ tự sắp xếp địa phương cụ thể. Đọc thêm về các lớp toán tử trong hướng dẫn . Nếu bạn đang sử dụng ngôn ngữ "C" tiêu chuẩn (hầu hết mọi người không), một chỉ mục đơn giản (với lớp toán tử mặc định) sẽ làm.
Một chỉ mục như vậy chỉ tốt cho các mẫu neo trái (khớp từ đầu chuỗi).
SIMILAR TO
hoặc các biểu thức chính quy với các biểu thức neo trái cơ bản cũng có thể sử dụng chỉ mục này. Nhưng không phải với các nhánh (B|D)
hoặc các lớp ký tự [BD]
(ít nhất là trong các thử nghiệm của tôi trên PostgreQuery 9.0).
Kết hợp trigram hoặc tìm kiếm văn bản sử dụng các chỉ mục GIN hoặc GiST đặc biệt.
Tổng quan về toán tử khớp mẫu
LIKE
( ~~
) là đơn giản và nhanh chóng nhưng hạn chế trong khả năng của nó.
ILIKE
( ~~*
) trường hợp biến thể không nhạy cảm.
pg_trgm mở rộng hỗ trợ chỉ mục cho cả hai.
~
(kết hợp biểu thức chính quy) mạnh mẽ nhưng phức tạp hơn và có thể chậm đối với mọi thứ hơn các biểu thức cơ bản.
SIMILAR TO
chỉ là vô nghĩa . Một nửa giống đặc biệt LIKE
và biểu thức chính quy. Tôi không bao giờ sử dụng nó. Xem bên dưới.
% là toán tử "tương tự", được cung cấp bởi mô-đun bổ sungpg_trgm
. Xem bên dưới.
@@
là toán tử tìm kiếm văn bản. Xem bên dưới.
pg_trgm - trigram phù hợp
Bắt đầu với PostgreSQL 9.1, bạn có thể tạo điều kiện cho tiện ích mở rộng pg_trgm
cung cấp hỗ trợ chỉ mục cho bất kỳ LIKE
/ ILIKE
mẫu nào (và các mẫu biểu thức chính quy đơn giản với ~
) bằng cách sử dụng chỉ mục GIN hoặc GiST.
Chi tiết, ví dụ và liên kết:
pg_trgm
cũng cung cấp các toán tử này :
%
- toán tử "tương tự"
<%
( %>
cổ góp :) - toán tử "word_similarity" trong Postgres 9.6 trở lên
<<%
( %>>
cổ góp :) - toán tử "rict_word_similarity" trong Postgres 11 trở lên
Tìm kiếm văn bản
Là một kiểu mẫu đặc biệt phù hợp với các loại chỉ mục và cơ sở hạ tầng riêng biệt. Nó sử dụng từ điển và xuất phát và là một công cụ tuyệt vời để tìm các từ trong tài liệu, đặc biệt là các ngôn ngữ tự nhiên.
Kết hợp tiền tố cũng được hỗ trợ:
Cũng như tìm kiếm cụm từ kể từ Postgres 9.6:
Xem xét phần giới thiệu trong hướng dẫn và tổng quan về các toán tử và chức năng .
Các công cụ bổ sung để khớp chuỗi mờ
Các fuzzystrmatch mô-đun bổ sung cung cấp một số tùy chọn khác, nhưng hiệu suất thường kém hơn tất cả các bên trên.
Cụ thể, việc thực hiện các levenshtein()
chức năng khác nhau có thể là công cụ.
Tại sao các biểu thức chính quy ( ~
) luôn nhanh hơn SIMILAR TO
?
Đáp án đơn giản. SIMILAR TO
biểu thức được viết lại thành biểu thức chính quy trong nội bộ. Vì vậy, đối với mỗi SIMILAR TO
biểu thức, có ít nhất một biểu thức chính quy nhanh hơn (giúp tiết kiệm chi phí viết lại biểu thức). Không có hiệu suất đạt được trong việc sử dụng SIMILAR TO
bao giờ .
Và các biểu thức đơn giản có thể được thực hiện với LIKE
( ~~
) nhanh hơn với LIKE
dù sao đi nữa.
SIMILAR TO
chỉ được hỗ trợ trong PostgreSQL vì nó đã kết thúc trong các bản nháp đầu tiên của tiêu chuẩn SQL. Họ vẫn chưa thoát khỏi nó. Nhưng có kế hoạch để loại bỏ nó và bao gồm các trận đấu regrec thay vào đó - hoặc vì vậy tôi đã nghe.
EXPLAIN ANALYZE
tiết lộ nó Chỉ cần thử với bất kỳ bảng nào!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Tiết lộ:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
đã được viết lại với một biểu thức chính quy ( ~
).
Hiệu suất cuối cùng cho trường hợp cụ thể này
Nhưng EXPLAIN ANALYZE
tiết lộ nhiều hơn. Hãy thử, với chỉ số được đề cập ở trên:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Tiết lộ:
...
-> Bitmap Heap Scan on spelers (cost= ...
Filter: (name ~ '^B.*'::text)
-> Bitmap Index Scan on spelers_name_text_pattern_ops_idx (cost= ...
Index Cond: ((prod ~>=~ 'B'::text) AND (prod ~<~ 'C'::text))
Bên trong, với một chỉ số mà không được Locale-aware ( text_pattern_ops
hoặc sử dụng locale C
) biểu thức đơn giản trái neo được viết lại với các nhà khai thác mô hình văn bản: ~>=~
, ~<=~
, ~>~
, ~<~
. Đây là trường hợp cho ~
, ~~
hoặc SIMILAR TO
như nhau.
Điều này cũng đúng với các chỉ mục trên varchar
các loại có varchar_pattern_ops
hoặc char
có bpchar_pattern_ops
.
Vì vậy, áp dụng cho câu hỏi ban đầu, đây là cách nhanh nhất có thể :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Tất nhiên, nếu bạn tình cờ tìm kiếm tên viết tắt liền kề , bạn có thể đơn giản hóa hơn nữa:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Việc đạt được trên sử dụng đơn giản ~
hoặc ~~
là rất nhỏ. Nếu hiệu suất không phải là yêu cầu tối quan trọng của bạn, bạn chỉ nên gắn bó với các toán tử tiêu chuẩn - đi đến những gì bạn đã có trong câu hỏi.
s.name
lập chỉ mục?