it-swarm.dev

Jak utworzyć indeks, aby przyspieszyć zagregowane zapytanie LIKE dla wyrażenia?

Mogę zadawać złe pytanie w tytule. Oto fakty:

Pracownicy działu obsługi klienta narzekają na długi czas reakcji podczas wyszukiwania klientów w interfejsie administracyjnym naszej witryny opartej na Django.

Używamy Postgres 8.4.6. Zacząłem rejestrować powolne zapytania i odkryłem tego winowajcę:

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

Uruchomienie tego zapytania zajmuje ponad 32 sekundy. Oto plan zapytań dostarczony przez 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)

Ponieważ jest to zapytanie wygenerowane przez Django ORM z Django QuerySet wygenerowany przez Django Administrator aplikacji, nie nie mam żadnej kontroli nad samym zapytaniem. Indeks wydaje się logicznym rozwiązaniem. Próbowałem utworzyć indeks, aby to przyspieszyć, ale nie zrobiło to różnicy:

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

Co ja robię źle? Jak mogę przyspieszyć to zapytanie?

22
David Eyk

Nie ma obsługi indeksu dla LIKE/ILIKE in PostgreSQL 8.4 - z wyjątkiem lewe wyszukiwanie zakotwiczone) warunki .

Ponieważ PostgreSQL 9.1 dodatkowy moduł pg_trgm zapewnia klasy operatorów dla indeksów GIN i Gist trigram obsługujących LIKE/ILIKE lub wyrażenia regularne (operatory ~ i przyjaciele). Zainstaluj raz na bazę danych:

CREATE EXTENSION pg_trgm;

Przykładowy indeks GIN:

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

Związane z:

24

Ten indeks nie pomoże z powodu „%” na początku dopasowania - indeks BTREE może dopasować tylko prefiksy, a symbol wieloznaczny na początku zapytania oznacza, że ​​nie ma ustalonego prefiksu do wyszukania.

Dlatego wykonuje skanowanie tabeli i dopasowuje kolejno każdy rekord względem ciągu zapytania.

Prawdopodobnie musisz spojrzeć na użycie indeksu pełnotekstowego i operatorów dopasowywania tekstu zamiast na wyszukiwanie podciągów w LIKE, którym jesteś w tej chwili. Więcej informacji na temat wyszukiwania pełnotekstowego można znaleźć w dokumentacji:

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

W rzeczywistości zauważam na tej stronie, że LIKE najwyraźniej nigdy nie używa indeksów, co wydaje mi się dziwne, ponieważ powinno być w stanie rozwiązać przedrostki bez symboli wieloznacznych przy użyciu indeksu BTREE. Kilka szybkich testów sugeruje, że dokumentacja jest prawdopodobnie poprawna, w takim przypadku żadna ilość indeksowania nie pomoże, gdy używasz LIKE do rozwiązania zapytania.

9
TomH