Làm cách nào để tạo một chỉ mục để tăng tốc truy vấn THÍCH tổng hợp trên một biểu thức?


20

Tôi có thể hỏi câu hỏi sai trong tiêu đề. Dưới đây là sự thật:

Dân gian dịch vụ khách hàng của tôi đã phàn nàn về thời gian phản hồi chậm khi thực hiện tra cứu khách hàng trên giao diện quản trị của trang web dựa trên Django của chúng tôi.

Chúng tôi đang sử dụng Postgres 8.4.6. Tôi bắt đầu đăng nhập các truy vấn chậm và phát hiện ra thủ phạm này:

SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')

Truy vấn này mất tới 32 giây để chạy. Đây là kế hoạch truy vấn được cung cấp bởi EXPLAIN:

QUERY PLAN
Aggregate  (cost=205171.71..205171.72 rows=1 width=0)
  ->  Seq Scan on auth_user  (cost=0.00..205166.46 rows=2096 width=0)
        Filter: (upper((email)::text) ~~ '%DEYK%'::text)

Vì đây là truy vấn được tạo bởi Django ORM từ Django Queryset được tạo bởi ứng dụng Django Admin, tôi không có bất kỳ quyền kiểm soát nào đối với chính truy vấn đó. Một chỉ số có vẻ như là giải pháp hợp lý. Tôi đã thử tạo một chỉ mục để tăng tốc độ này, nhưng nó không tạo ra sự khác biệt:

CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))

Tôi đang làm gì sai? Làm thế nào tôi có thể tăng tốc truy vấn này?

Câu trả lời:


21

Không có hỗ trợ chỉ mục cho LIKE/ ILIKEtrong PostgreQuery 8.4 - ngoại trừ các cụm từ tìm kiếm neo trái .

PostgreQuery 9.1 , mô-đun bổ sung pg_trgmcung cấp các lớp toán tử cho các chỉ số bát quái GIN và GiST hỗ trợ LIKE/ ILIKEhoặc các biểu thức chính quy (toán tử ~và bạn bè). Cài đặt một lần cho mỗi cơ sở dữ liệu:

CREATE EXTENSION pg_trgm;

Ví dụ chỉ số GIN:

CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);

Liên quan:


2
Đây thực sự là câu trả lời chính xác.
vonPetrushev

9

Chỉ mục đó sẽ không hữu ích vì '%' khi bắt đầu trận đấu của bạn - chỉ mục BTREE chỉ có thể khớp với tiền tố và ký tự đại diện khi bắt đầu truy vấn của bạn có nghĩa là không có tiền tố cố định để tìm kiếm.

Đó là lý do tại sao nó thực hiện quét bảng và khớp lần lượt mọi bản ghi với chuỗi truy vấn.

Bạn có thể cần xem xét việc sử dụng một chỉ mục văn bản đầy đủ và các toán tử khớp văn bản thay vì thực hiện tìm kiếm chuỗi con với THÍCH mà bạn đang ở hiện tại. Bạn có thể tìm thêm về tìm kiếm toàn văn trong tài liệu:

http://www.postgresql.org/docs/8.4/static/textsearch-intro.html

Trong thực tế tôi nhận thấy từ trang đó rằng THÍCH dường như không bao giờ sử dụng các chỉ mục, điều này có vẻ kỳ lạ đối với tôi vì nó phải có khả năng giải quyết các tiền tố không phải ký tự đại diện bằng cách sử dụng chỉ mục BTREE. Một vài thử nghiệm nhanh cho thấy rằng tài liệu này có thể đúng, tuy nhiên, trong trường hợp đó, không có số lượng lập chỉ mục nào có ích trong khi bạn đang sử dụng THÍCH để giải quyết truy vấn.


Đó là những gì tôi sợ. Có một loại chỉ số sẽ giúp? Như tôi đã nói, tôi hơi bị hạn chế về khả năng ảnh hưởng đến chính truy vấn.
David Eyk

Ngoài ra, hàng đầu %là một tính năng cần thiết: đại diện dịch vụ khách hàng cần nó để tìm tài khoản khách hàng, đặc biệt là khi có lỗi đánh máy trong địa chỉ email.
David Eyk

Chà, sau một chút nghiên cứu về THÍCH và lập chỉ mục toàn văn, và tôi bắt đầu thấy quan điểm của bạn.
David Eyk

Hiện tại, tôi đã tìm ra cách để loại bỏ ký tự đại diện hàng đầu. Hóa ra bạn có thể sử dụng một chỉ mục với THÍCH, nếu bạn tạo chỉ mục với một lớp toán tử thích hợp . Tài liệu ở đây: postgresql.org/docs/8.4/static/indexes-opgroup.html
David Eyk

Ngoài ra, kiểm tra db của bạn cho sưng lên. Nếu bạn có rất nhiều sự phình to trong bảng đó, sẽ mất nhiều thời gian để seq quét nó. Nếu bạn đã có một chút thời gian, chỉ cần phân cụm nó trên khóa chính và xem nếu nó nhanh hơn. Nếu bạn muốn kiểm tra sự phình to, bạn có thể chạy phân tích sau đó chạy truy vấn tại đây: wiki.postgresql.org/wiki/Show_database_bloat . Để biết giá trị chính xác hơn, xem dưới cùng của trang đó.
Scott Marlowe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.