Perché PostgreSQL esegue la scansione sequenziale su colonne indicizzate?


150

Esempio molto semplice: una tabella, un indice, una query:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

mi da:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

Perché NON esegue invece la scansione dell'indice? Cosa mi sto perdendo?

Risposte:


222

Se SELEZIONA restituisce più del 5-10% circa di tutte le righe della tabella, una scansione sequenziale è molto più veloce di una scansione indice.

Questo perché una scansione dell'indice richiede diverse operazioni di I / O per ogni riga (cercare la riga nell'indice, quindi recuperare la riga dall'heap). Considerando che una scansione sequenziale richiede un solo IO per ogni riga - o anche meno perché un blocco (pagina) sul disco contiene più di una riga, quindi è possibile recuperare più di una riga con una singola operazione IO.

A proposito: questo vale anche per altri DBMS - alcune ottimizzazioni come "scansioni solo dell'indice" messe da parte (ma per un SELECT * è altamente improbabile che un tale DBMS vada per una "scansione solo dell'indice")


12
Il 5-10% dipende da un paio di impostazioni di configurazione e dalla memorizzazione dei dati. Non è un numero difficile.
Frank Heikens,

6
@Frank: ecco perché ho detto "approssimativamente" :) Ma grazie per averlo sottolineato
a_horse_with_no_name

5
Inoltre, una scansione sequenziale può richiedere diverse pagine dall'heap alla volta e chiedere al kernel di recuperare il blocco successivo mentre funziona su quello corrente: una scansione dell'indice recupera una pagina alla volta. (Una scansione bitmap fa un compromesso tra i due, di solito si vede che appare in un piano per query che non sono abbastanza selettive per una scansione di indice, ma ancora non così selettive da meritare una scansione di tabella completa)
araqnid

4
La domanda interessante è come il database sa quante righe restituirà la query senza prima farlo? Memorizza da qualche parte statistiche come il numero di valori diversi rispetto alle dimensioni della tabella?
Laurent Grégoire,

7
@ LaurentGrégoire: sì, il database memorizza le statistiche sul numero di righe e sulla distribuzione dei valori. Per i dettagli consultare il manuale: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name

13

Hai ANALIZZATO la tabella / database? E le statistiche ? Quando ci sono molti record in cui l'anno> 2009, una scansione sequenziale potrebbe essere più veloce di una scansione di indice.


0

Nella scansione indice, leggi i salti di testa da una riga all'altra, che è 1000 volte più lento della lettura del blocco fisico successivo (nella scansione sequenziale).

Pertanto, se il (numero di record da recuperare * 1000) è inferiore al numero totale di record, la scansione dell'indice funzionerà meglio.


0

@a_horse_with_no_name lo ha spiegato abbastanza bene. Inoltre, se vuoi davvero usare una scansione dell'indice, dovresti generalmente usare intervalli limitati nella clausola where. ad es. - anno> 2019 e anno <2020.

Molte volte le statistiche non vengono aggiornate su una tabella e potrebbe non essere possibile farlo a causa di vincoli. In questo caso, l'ottimizzatore non saprà quante righe dovrebbe prendere nell'anno> 2019. Quindi seleziona una scansione sequenziale al posto della piena conoscenza. Le partizioni limitate risolveranno il problema per la maggior parte del tempo.

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.