PostgreSQL può usare null nei suoi indici?


10

Ho letto questo libro che lo dice

Il database presuppone che Indexed_Col IS NOT NULL copra un intervallo troppo ampio per essere utile, quindi il database non guiderà verso un indice da questa condizione.

Riconosco che il libro ha più di 10 anni, ma si è già dimostrato abbastanza utile - Usando le istruzioni raccolte dalle sue pagine, ho accelerato una query di un fattore dieci.

Inoltre, nell'esecuzione di EXPLAIN ANALYZEuna SELECTquery, ho scoperto che nessuno dei miei indici viene utilizzato, anche quando dovrebbero essere tutti i diritti.

Pertanto, la mia domanda è:

Supponendo che esista una tabella con una colonna, la cui definizione di colonna include "NOT NULL" e che esiste un indice che copre questa colonna, questo indice verrebbe utilizzato in una query di quella tabella in cui le colonne fanno parte della query?

Piace:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Risposte:


9

PostgreSQL può certamente usare un indice per IS NOT NULL. Non vedo nemmeno ipotesi di pianificatore di query su tale condizione.

Se la frazione nulla per la colonna ( pg_statistic.stanullfrac) è abbastanza bassa da suggerire che l'indice sia utilmente selettivo per la query, PostgreSQL utilizzerà un indice.

Non riesco a capire cosa stai cercando di dire con:

Se questo è corretto, capisco che un indice su una colonna definito come "NON NULL" non può essere utilizzato in una query che utilizza quella colonna?

Certamente un indice non verrà utilizzato per una IS NOT NULLcondizione su una NOT NULLcolonna. Corrisponderebbe sempre al 100% delle righe, quindi un seqscan sarà quasi sempre molto più veloce.

PostgreSQL non utilizzerà un indice se l'indice non filtra gran parte delle righe per una query. L'unica probabile eccezione è quando stai chiedendo una serie di colonne coperte da un singolo indice, in un ordine corrispondente a quello dell'indice. PostgreSQL potrebbe quindi eseguire una scansione solo dell'indice. Ad esempio, se è presente un indice t(a, b, c)e tu:

select a, b FROM t ORDER BY a, b, c;

PostgreSQL potrebbe usare il tuo indice, anche se nessuna riga viene filtrata, perché deve solo leggere l'indice e può saltare la lettura dell'heap, evitare di fare un ordinamento, ecc.


Questo è tutto vero a partire da PG 9.0
Eradman,

1
E anche su una colonna nullable, una query con condizione WHERE column IS NOT NULLpotrebbe non utilizzare l'indice perché, come dice il libro: "copre un intervallo troppo ampio per essere utile". Se il 90% dei valori non è nullo, anche un seqscan sarà probabilmente più veloce.
ypercubeᵀᴹ

Esattamente. Potrebbe, ma solo se una grande parte della tabella è nulla. Spesso in questo caso un indice parziale è comunque una scelta migliore.
Craig Ringer, l'

Sì. Stavo cercando di dire che (come ho capito) la parte "copre un intervallo troppo ampio" si riferisce all'indice, ma per quanto riguarda la condizione specifica e non l'indice in generale.
ypercubeᵀᴹ

2
@FuriousFolder Heh, ci sono troppe negazioni qui. PostgreSQL non utilizzerà un indice su una NOT NULLcolonna per una IS NOT NULLquery a meno che quell'indice non sia utile anche per altre parti della WHEREclausola, filtri di join, ecc. O non sia utilizzabile per una scansione solo indice ordinata. In altre parole, ignorerà completamente il ridondante IS NOT NULLsulla NOT NULLcolonna e farà le scelte di utilizzo dell'indice in base ad altri dettagli. (Vedi modifica, ri scansioni solo indice).
Craig Ringer,

2

Oltre alla risposta esauriente di Craig, volevo aggiungere che la copertina del libro a cui fai riferimento dice:

Copre Oracle, DB2 e SQL Server

Quindi non mi fiderei che sia una grande fonte di consigli su PostgreSQL in particolare. Ogni RDBMS può essere sorprendentemente diverso!

Sono un po 'confuso riguardo alla tua domanda originale, ma ecco un esempio che mostra che la sezione del libro non è corretta al 100%. Per evitare ulteriore confusione, ecco l'intero paragrafo pertinente, puoi vederlo in Google Ricerca Libri .

Il database presuppone che Indexed_Col IS NOT NULL copra un intervallo troppo ampio per essere utile, quindi il database non guiderà verso un indice da questa condizione. In rari casi, avere un valore non nullo è così raro che è utile una scansione dell'intervallo di indice su tutti i possibili valori non nulli. In questi casi, se riesci a capire un limite inferiore o superiore sicuro all'intervallo di tutti i possibili valori, puoi abilitare una scansione dell'intervallo con una condizione come Positive_ID_Column> -1 o Date_Column> TO_DATE ('0001/01/01' , "AAAA / MM / GG").

Postgres può effettivamente (nel seguente caso inventato) utilizzare un indice per soddisfare le IS NOT NULLquery senza aggiungere kludges di scansione di intervallo come quello suggerito Positive_ID_Column > -1. Vedi i commenti sulle domande di Craig sul perché Postgres scelga questo indice in questo caso particolare e la nota sull'uso di indici parziali.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Questo è Postgres 9.3 a proposito, ma credo che i risultati sarebbero approssimativamente simili su 9.1, anche se non userebbe una "Scansione solo indice".

Modifica: Vedo che hai chiarito la tua domanda originale e apparentemente ti stai chiedendo perché Postgres non stia usando un indice in un semplice esempio come:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Probabilmente perché non ci sono righe nella tabella. Quindi aggiungi alcuni dati di test e ANALYZE my_table;.


Nella descrizione di detto libro (il mio accento è mio): "L'autore Dan Tow delinea un metodo salvavita che ha sviluppato per trovare il piano di esecuzione ottimale - rapidamente e sistematicamente - indipendentemente dalla complessità dell'SQL o della piattaforma di database utilizzata " Inoltre, forse hai ignorato il n. 1 della domanda, vale a dire che la colonna è definita come NOT NULL, non che la query utilizza IS NOT NULLcome condizione di indice. Questo è nei commenti a cui hai fatto riferimento, ma aggiornerò la domanda per includerla.
FuriousFolder,

Inoltre, il libro stesso è indipendente dal linguaggio: le uniche parti specifiche di DMBS riguardano la visualizzazione di piani di query, cosa che Postgres rende abbastanza semplice :)
FuriousFolder,

1
@FuriousFolder la colonna è definita come NOT NULL ma questa parte (nella tua domanda, dal libro): "che Indexed_Col IS NOT NULL copre ..." si riferisce alla condizione where e non alla definizione della colonna. Anche se è difficile essere sicuri, perché è fuori contesto. Forse dovresti includere l'intero paragrafo (precedente) del libro.
ypercubeᵀᴹ

-1

Non hai pubblicato la tua query o i dati di esempio. Ma il motivo più comune per cui gli indici non vengono utilizzati ha a che fare con il volume.

Gli indici sono come una rubrica che traduce una colonna in una posizione di riga. Se stai cercando solo poche righe, ha senso cercare ciascuna riga nella rubrica, quindi cercare la riga nella tabella principale.

Ma per più di qualche riga, è più economico saltare la rubrica e scorrere su tutte le righe della tabella principale. Nella mia esperienza il punto di ribaltamento è di circa 100 righe.


"Gli indici sono come una rubrica che traduce una colonna in una posizione di riga. Se stai cercando solo poche righe, ha senso cercare ciascuna riga della rubrica, quindi cercare la riga nella tabella principale." In realtà, gli indici sono come rubriche più piccole che vengono aggiornate ogni volta che la rubrica che indicizzano viene aggiornata. Sai che ogni volta che apri una rubrica più piccola, troverai tutte le informazioni descritte dalla sua condizione di indicizzazione. Ad esempio, Tutte le persone chiamate 'Frank' su un tavolo di indice: CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder l'

Ciò consente a una scansione di soli indici di essere molto più veloce, dal momento che è possibile leggere l'intera "rubrica più piccola" in memoria, il che non è possibile con una tabella a più milioni di righe.
FuriousFolder l'

@FuriousFolder: stai descrivendo una scansione solo indice. Ma l'OP afferma che i suoi indici non vengono utilizzati, il che non accadrebbe se una scansione di soli indici soddisfacesse la query.
Andomar,

Andomar ... Io sono il PO, haha. Il mio obiettivo è esattamente quello; per ottenere questa query per utilizzare una scansione di solo indice. Da allora l'ho raggiunto, dal momento che Craig ha spiegato che Postgres è in grado di utilizzare un indice su una colonna in cui la definizione della colonna include NOT NULL
FuriousFolder
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.