it-swarm.it

Come creare un indice per velocizzare una query LIKE aggregata su un'espressione?

Potrei fare la domanda sbagliata nel titolo. Ecco i fatti:

Le persone del mio servizio clienti si sono lamentate dei tempi di risposta lenti durante le ricerche dei clienti sull'interfaccia di amministrazione del nostro sito basato su Django.

Stiamo usando Postgres 8.4.6. Ho iniziato a registrare query lente e ho scoperto questo colpevole:

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

L'esecuzione di questa query richiede 32 secondi. Ecco il piano di query fornito da 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)

Perché questa è una query generata dal Django ORM da un Django QuerySet generato dall'applicazione Django Admin, io don non ha alcun controllo sulla query stessa. Un indice sembra la soluzione logica. Ho provato a creare un indice per accelerarlo, ma non ha fatto differenza:

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

Che cosa sto facendo di sbagliato? Come posso velocizzare questa query?

22
David Eyk

Non esiste un supporto indice per LIKE/ILIKE in PostgreSQL 8.4 - tranne ricerca ancorata a sinistra termini .

Poiché PostgreSQL 9.1 il modulo aggiuntivo pg_trgm fornisce classi di operatori per gli indici trigramma GIN e Gist che supportano LIKE/ILIKE o espressioni regolari (operatori ~ e amici). Installa una volta per database:

CREATE EXTENSION pg_trgm;

Esempio di indice GIN:

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

Relazionato:

24

Tale indice non sarà di aiuto a causa di '%' all'inizio della partita: un indice BTREE può corrispondere solo ai prefissi e il carattere jolly all'inizio della query significa che non esiste un prefisso fisso da cercare.

Ecco perché sta eseguendo una scansione della tabella e abbinando ogni record a sua volta contro la stringa di query.

Probabilmente devi guardare usando un indice di testo completo e gli operatori di corrispondenza del testo piuttosto che fare la ricerca di sottostringa con LIKE che sei in questo momento. Puoi trovare ulteriori informazioni sulla ricerca full-text nella documentazione:

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

In effetti, da quella pagina noto che LIKE apparentemente non usa mai gli indici, il che mi sembra strano in quanto dovrebbe essere in grado di risolvere i prefissi non jolly usando un indice BTREE. Alcuni test rapidi suggeriscono che la documentazione è probabilmente corretta, nel qual caso nessuna indicizzazione sarà utile mentre si utilizza LIKE per risolvere la query.

9
TomH