2011-12-19 15 views
7

Ho una tabella di parole con un indice su (language_id, stato). Ecco i risultati per SPIEGARE ANALYZE:Indice non utilizzato quando LIMIT viene utilizzato in postgres

Nessun limite

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL); 

Bitmap Heap Scan on words (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1) 
Recheck Cond: ((language_id = 27) AND (state IS NULL)) 
-> Bitmap Index Scan on ls (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1) 
Index Cond: ((language_id = 27) AND (state IS NULL)) 
Total runtime: 460.277 ms 
(5 rows) 

Limite 100

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100; 

Limit (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1) 
-> Seq Scan on words (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1) 
Filter: ((state IS NULL) AND (language_id = 27)) 
Total runtime: 0.240 ms 
(4 rows) 

Perché succede questo? Come posso ottenere l'indice da utilizzare in tutti i casi?

Grazie.

+4

Un LIMIT senza un ORDINE BY sembrerebbe di valore limitato (nessun gioco di parole). Di quali 100 file ti aspetti di essere restituito? –

+0

BTW: qual è la selettività di language_id = 17 AND status IS NULL clausola? qual è la dimensione totale della tabella delle parole? – wildplasser

+0

true ... l'ordine si verifica su id DESC. Potrebbe rallentarlo? È necessario un indice su quella colonna? La dimensione totale di @wildplasser è di 10 milioni di righe, la selettività è di circa 500.000 righe – alste

risposta

7

Penso che il pianificatore di query PostreSQL pensi solo che nel secondo caso - quello con il LIMIT - non valga la pena applicare l'indice poiché [il LIMIT] è troppo piccolo. Quindi non è un problema.

+0

Hai ragione, ma come posso evitare questo? In realtà sto usando l'indice jsonb gin e, a causa del limite 1, questo indice non viene utilizzato e impiega molto tempo. – Anurag

0

È anche strano che le due query restituiscano un numero diverso di righe. Immagino che tu stia inserendo però ... Uhm, e se fai una sottoselezione?

select * from (select ...) limit 100; 
+1

"(5 righe)" si riferisce al numero di righe nel piano di spiegazioni, non al numero di righe restituite dalla query – Anna

3

Senza limite: rows = 540556 loop = 1 Tempo totale: 460.277 ms

Con limite: rows = 100 loop = 1 Tempo totale: 0.240 ms

non vedo un problema Qui. Se la tua query produce 500K righe, avrà bisogno di più tempo.

3

Dai un'occhiata alla documentazione di PostgreSQL su Using EXPLAIN e Query Planning. Il motivo per cui il pianificatore di query preferisce una scansione sequenziale su una scansione dell'indice nel caso LIMIT 100 è semplicemente perché la scansione sequenziale è più economica.

Non c'è una clausola ORDER BY nella query, quindi il pianificatore va bene con le prime 100 righe (casuali) che corrispondono alla condizione del filtro. Una scansione dell'indice richiederebbe leggere prima le pagine indice e quindi leggere le pagine di dati per recuperare le righe corrispondenti. La scansione sequenziale ha solo bisogno di leggere le pagine di dati per recuperare le righe. Nel tuo caso le statistiche della tabella sembrano suggerire che ci siano abbastanza righe (casuali) che corrispondono alla condizione del filtro. Il costo delle letture sequenziali delle pagine per ottenere le 100 righe è considerato più economico del costo di leggere prima l'indice e poi recuperare le righe effettive. Potresti vedere un piano diverso quando aumenti il ​​limite o quando meno righe corrispondono alla condizione del filtro.

Con le impostazioni predefinite pianificatore considera il costo di una pagina a caso lettura (random_page_cost) quattro volte il costo di una pagina sequenziale lettura (seq_page_cost). Queste impostazioni possono essere regolate per ottimizzare i piani di query (ad esempio quando l'intero database si trova nella RAM, una lettura casuale della pagina non è più costosa di una lettura sequenziale della pagina e si dovrebbe preferire una scansione dell'indice). È anche possibile provare diversi piani di query abilitando/disabilitando alcuni tipi di scansioni, ad esempio:

set enable_seqscan = [on | off] 
set enable_indexscan = [on | off] 

Mentre è possibile abilitare/disabilitare certi tipi di scansioni su base globale questo deve essere utilizzato solo ad hoc per debug o risoluzione dei problemi per sessione.

Eseguire anche VACUUM ANALYZE words prima di testare i piani di query, altrimenti un vuoto automatico (autovaccum) eseguito tra i test potrebbe influenzare i risultati.

Problemi correlati