ORDINA LENTO DA con LIMIT


11

Ho questa domanda:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

Ne sono contento:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

Ma quando aggiungo LIMIT, l'esecuzione richiede più di 2 secondi:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

Spiegare:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

Penso che sia un problema con ORDER BY e LIMIT. Come posso forzare PostgreSQL a utilizzare l'indice e fare l'ordine alla fine?

La subquery non aiuta:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

o:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;

Risposte:


12

Immagino che questo risolva la tua domanda:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

Ripeto la WHEREcondizione come primo elemento della ORDER BYclausola - che è logicamente ridondante, ma dovrebbe impedire al pianificatore di query di supporre che sarebbe meglio elaborare le righe in base all'indice location_displaycount_index- che risulta essere molto più costoso.

Il problema di fondo è che il pianificatore di query ovviamente giudica gravemente erroneamente la selettività e / o il costo della tua WHEREcondizione. Posso solo speculare sul perché.

Hai il funzionamento del vuoto automatico - che dovrebbe anche occuparsi di correre ANALYZEsui tuoi tavoli? In tal modo, le statistiche delle tabelle sono aggiornate? Qualsiasi effetto se esegui:

ANALYZE location;

E prova ancora?

Può anche essere che la selettività @@dell'operatore venga giudicata erroneamente. Immagino che sia molto difficile stimare per motivi logici.


Se la mia query non dovesse risolvere il problema, e in generale per verificare la teoria di base, fai una di queste due cose:

Quest'ultimo è meno invadente e riguarda solo la sessione corrente. Lascia i metodi bitmap heap scane bitmap index scanaperto, che vengono utilizzati dal piano più veloce.
Quindi rieseguire la query.

A proposito: se la teoria è valida, la tua query (come la hai ora) sarà molto più veloce con un termine di ricerca meno selettivo nella condizione FTS - contrariamente a quanto ti aspetteresti. Provalo.


1
La query funziona. Anche la disattivazione di IndexScan funziona. ANALYZE non funziona. Grazie mille per la risposta esaustiva.
Ziri,

0

Quando si utilizza una regolazione postgresql LIMIT, il piano è ottimale per il solo recupero del sottoinsieme di righe. Purtroppo in qualche modo fa una scelta sbagliata nel tuo caso. Ciò potrebbe essere dovuto al fatto che le statistiche per la tabella sono troppo vecchie. Prova ad aggiornare la statistica emettendo la posizione VACUUM ANALYZE;

La forzatura dell'uso degli indici viene normalmente eseguita impedendo l'uso di scansioni sequenziali (impostare enable_seqscan = false). Tuttavia, nel tuo caso non esegue una scansione sequenziale, passa semplicemente a un indice diverso per la query con LIMIT.

Nel caso in cui l'analisi non aiuti, potresti dire quale versione di postgresql stai usando? Inoltre quante righe ci sono nella tabella?


Analizzare non ha aiutato. La tabella ha circa 36000 righe e sto usando Postgresql 9.1.
Ziri,
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.