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


20

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)

Poiché si tratta di una query generata da Django ORM da un Django QuerySet generato dall'applicazione Django Admin, non ho 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?

Risposte:


21

Non esiste supporto per l'indice per LIKE/ ILIKEin PostgreSQL 8.4 , ad eccezione dei termini di ricerca ancorati a sinistra .

Da PostgreSQL 9.1 il modulo aggiuntivo pg_trgmfornisce classi di operatori per gli indici trigramma GIN e GiST che supportano LIKE/ ILIKEo 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:


2
Questa è in realtà la risposta corretta.
vonPetrushev,

9

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 probabilmente la documentazione è probabilmente corretta, nel qual caso nessuna indicizzazione sarà utile mentre si utilizza LIKE per risolvere la query.


Questo è ciò di cui avevo paura. C'è un altro tipo di indice che ti aiuterà? Come ho detto, sono un po 'limitato nella mia capacità di influenzare la query stessa.
David Eyk,

Inoltre, il leader %è una caratteristica necessaria: i rappresentanti del servizio clienti ne hanno bisogno per trovare gli account dei clienti, soprattutto quando c'è un errore di battitura nell'indirizzo e-mail.
David Eyk,

Bene, dopo un po 'di ricerche su LIKE e l'indicizzazione full-text, e sto iniziando a capire il tuo punto.
David Eyk,

Per ora, ho trovato un modo per sopprimere il carattere jolly principale. Si scopre che è possibile utilizzare un indice con LIKE, se si crea l'indice con una classe operatore appropriata . I documenti sono qui: postgresql.org/docs/8.4/static/indexes-opclass.html
David Eyk

Inoltre, controlla se il tuo db è gonfio. Se hai un sacco di gonfiore in quel tavolo, ci vorrà molto tempo per scansionarlo. Se hai dei tempi di inattività, basta raggrupparlo sulla chiave primaria e vedere se diventa più veloce. Se si desidera verificare la presenza di bloat, è possibile eseguire l'analisi, quindi eseguire la query qui: wiki.postgresql.org/wiki/Show_database_bloat . Per valori più accurati, vedi il fondo di quella pagina.
Scott Marlowe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.