PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:perché questa query non utilizza il mio indice?

Come hai già capito, il problema è relativo all'utilizzo di operatori diversi da equals. Un indice può essere utilizzato in modo più efficiente solo per le colonne più a sinistra confrontate con uguale (più una condizione di intervallo).

Nel tuo esempio:

create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;

Può usare l'indice solo per a e b efficientemente. Ciò significa che il DB recupera tutte le righe che corrispondono a a e b condizione e quindi controlla ogni riga rispetto alle condizioni rimanenti.

Quando modifichi il filtro su c per essere uguale, recupera (potenzialmente) meno righe (solo quelle che corrispondono a a e b e c ) e quindi controlla quelle (meno) righe rispetto a d filtro. L'uso dell'indice è più efficiente in questo caso.

In generale, il pianificatore di query PostgreSQL valuta entrambe le opzioni:(1) utilizzando l'indice; (2) eseguire un SeqScan. Per entrambi, calcola un valore di costo:più è alto, peggiore è la performance attesa. Di conseguenza, prende quello con il valore di costo inferiore. È così che decide di utilizzare o meno l'indice, non c'è una soglia fissa.

Infine, sopra è scritto "più una condizione di intervallo". Ciò significa che non solo può utilizzare l'indice nel modo più efficiente se si utilizzano segni di uguale, ma anche per una condizione di intervallo singolo.

Considerando che hai una singola condizione di intervallo nella tua query, ti suggerisco di cambiare l'indice in questo modo:

create index i on t (a,b,d,c);

Ora può usare i filtri su a e b e d in modo efficiente con l'indice e deve solo filtrare le righe in cui c!=5 . Sebbene questo indice possa essere utilizzato in modo più efficiente per la tua query come quello originale, non significa automaticamente che PG lo utilizzerà. Dipende dalle stime dei costi. Ma provalo.

Infine, se questo non è abbastanza veloce, e il valore 5 stai usando nell'espressione c!=5 è costante, potresti considerare un indice parziale:

 create index i on t (a,b,d)
        where c!=5;

Puoi farlo anche con tutte le altre colonne, se i valori con cui le confronti sono costanti.

Riferimenti: