2011-12-15 15 views
5

Ho la seguente tabella:Postgres: è questo il modo giusto per creare un indice parziale su una colonna booleana?

CREATE TABLE recipemetadata 
(
    --Lots of columns 
    diet_glutenfree boolean NOT NULL, 
); 

La maggior parte ogni riga verrà impostato su FALSE a meno che qualcuno esce con qualche pazzo dieta priva di glutine nuovo che spazza il Paese.

Devo essere in grado di interrogare molto rapidamente le righe in cui questo valore è true. Ho creato l'indice:

CREATE INDEX IDX_RecipeMetadata_GlutenFree ON RecipeMetadata(diet_glutenfree) WHERE diet_glutenfree; 

E sembra funzionare, ma io non riesco a capire come dire se in effetti è solo indicizzazione righe in cui il valore è true. Voglio assicurarmi che non stia facendo qualcosa di sciocco come l'indicizzazione di qualsiasi riga con qualsiasi valore.

Devo aggiungere un operatore alla clausola WHERE oppure questa sintassi è perfettamente valida? Speriamo che questa non sia una di quelle domande RTFM super facili che verranno downvotate 30 volte.

UPDATE:

Sono andato avanti e ha aggiunto 10.000 righe di RecipeMetadata con valori casuali. Ho quindi fatto un ANALIZZA sul tavolo e un REINDEX solo per essere sicuro. Quando eseguo la query:

select recipeid from RecipeMetadata where diet_glutenfree;

ottengo:

'Seq Scan on recipemetadata (cost=0.00..214.26 rows=5010 width=16)' 
' Filter: diet_glutenfree' 

Quindi, sembra stia facendo una scansione sequenziale sul tavolo anche se solo circa la metà le righe hanno questa bandiera. L'indice viene ignorato.

Se lo faccio:

select recipeid from RecipeMetadata where not diet_glutenfree;

ottengo:

'Seq Scan on recipemetadata (cost=0.00..214.26 rows=5016 width=16)' 
' Filter: (NOT diet_glutenfree)' 

Quindi, non importa cosa, questo indice non è in uso.

+1

Si prega di aggiungere un link al tuo PostgreSQL mailing list posta dagli archivi così la gente può collegare questa discussione con quello. Sarebbe bello se pubblicassi un follow up sul tuo post sulla mailing list con un link anche a questo. Se devi eseguire il cross-post in più posizioni, ti preghiamo di dirlo per evitare che le persone ripetano il lavoro. –

+0

Non è un problema, farò questo in futuro (Io di solito non posterò in entrambi i posti) .. –

+0

BTW, penso che la risposta breve alla tua domanda è "sì" ... ma se siete preoccupati , riempire una tabella con alcuni dati fittizi, 'ANALIZZA' la tabella, quindi usare' ESPLORA ANALISI 'per esaminare i piani di alcune query che dovrebbero raggiungere l'indice parziale. –

risposta

4

Ho confermato che l'indice funziona come previsto.

Ho ricreato i dati casuali, solo questa volta impostato diet_glutenfree su random() > 0.9 quindi c'è solo una probabilità del 10% di un on bit.

Ho quindi ricreato gli indici e riprovato.

SELECT RecipeId from RecipeMetadata where diet_glutenfree; 

Returns:

'Index Scan using idx_recipemetadata_glutenfree on recipemetadata (cost=0.00..135.15 rows=1030 width=16)' 
' Index Cond: (diet_glutenfree = true)' 

E:

SELECT RecipeId from RecipeMetadata where NOT diet_glutenfree; 

Ritorni:

'Seq Scan on recipemetadata (cost=0.00..214.26 rows=8996 width=16)' 
' Filter: (NOT diet_glutenfree)' 

Sembra che il mio primo tentativo è stato inquinato dal PG stima che è più veloce per eseguire la scansione l'intero tavolo piuttosto che colpire l'inde x se deve caricare comunque più della metà delle righe.

Tuttavia, penso che vorrei ottenere questi risultati esatti su un indice completo della colonna. C'è un modo per verificare il numero di righe indicizzate in un indice parziale?

UPDATE

L'indice è di circa 40k. Ho creato un indice completo della stessa colonna ed è oltre 200k, quindi sembra che sia decisamente parziale.

+1

Sì, bang on. "Circa la metà" le righe non causeranno Pg per favorire l'indice. Avrai bisogno di una selettività molto migliore del 50% prima che una scansione dell'indice sia più veloce di un seqscan. –

+0

Grazie mille! Ho anche creato un indice completo per confrontare le dimensioni. Funziona sicuramente come previsto. –

+0

Nota: sembra che tu abbia solo record 10K. Il "working set" per la tua query si inserirà probabilmente nel core. L'ottimizzazione che esegui è un'ottimizzazione in termini di utilizzo della CPU. Una volta che il "working set" è più grande dello spazio del buffer disponibile, la tua query sarà vincolata all'I/O, e l'indice non ti aiuterà più (a meno che le tue righe siano così grandi che solo poche si adattino a una pagina del disco). – wildplasser

1

un indice su un campo di un bit non ha senso. Per capire le decisioni prese dal progettista, devi pensare in termini di pagine, non in termini di righe.

Per 8K pagine e un (Estinated) rowsize di 80, ci sono 100 righe in ogni pagina. Supponendo una distribuzione casuale, la possibilità che una pagina sia composta solo da righe con un valore true trascurabile, pow (0.5, 100), circa 1e-33, IICC. (E lo stesso per 'falsa' ovviamente) Così per una query su gluten_free == true, ogni pagina deve essere recuperato in ogni caso, e filtrata in seguito. L'utilizzo di un indice causerebbe solo altre pagine (: l'indice) da prelevare.

+1

"Un indice su un campo a un bit non ha senso". I bool di Postgres richiedono 8 bit di archiviazione: http://www.postgresql.org/docs/8.4/static/datatype-boolean.html "Supponendo una distribuzione casuale" - questo è potenzialmente un grosso presupposto. Molto meno del 50% degli alimenti sono in genere privi di glutine. Risposta perspicace, a prescindere. –

+0

"campo a un bit" riguardava il contenuto delle informazioni, non la dimensione di archiviazione richiesta.Potrebbe esserci una struttura di archiviazione possibile per archiviare/indicizzare/recuperare i bitfield (si pensi: judy-trees) questi potrebbero richiedere un minor numero di pagine disco da recuperare, ma sarà difficile combinarli con i requisiti ATOM per un RDBMS. – wildplasser

Problemi correlati