Un indice composito è utile anche per le query sul primo campo?


87

Diciamo che ho una tabella con campi Ae B. Faccio query regolari su A+ B, quindi ho creato un indice composito su (A,B). Anche le query su Asarebbero completamente ottimizzate dall'indice composito?

Inoltre, ho creato un indice su A, ma Postgres utilizza ancora l'indice composito solo per le query A. Se la risposta precedente è positiva, immagino che non abbia importanza, ma perché seleziona l'indice composito per impostazione predefinita, se il singolo Aindice è disponibile?


Ho provato a impostare un piccolo test per questo. Nel mio caso, tuttavia, l'indice a due colonne è stato utilizzato solo quando ho lasciato cadere quello a colonna singola, non correlato a quello che è stato creato per primo. È interessante notare che se ho creato prima l'indice a due colonne, il piano iniziale utilizzava una scansione heap bitmap. Se ho creato l'indice a una colonna, quindi eseguo la query (scansione dell'indice utilizzata) e trascino l'indice appena creato, il piano che coinvolge l'indice a due colonne passa alla scansione dell'indice. Vedi i passaggi su SQLFiddle
dezso,

@dezso Interessante. Dove sono i costi per ogni query?
Luciano,

Costo scansione indice bitmap: 107,98, tempo di esecuzione 43 ms. Scansione indice a una colonna: costo 8,69, a due colonne: 43,69. I tempi di esecuzione non differiscono in modo significativo (la fluttuazione è maggiore della differenza tra i due).
dezso,

@Luciano Puoi mostrare il explain analyzetesto della query e?
Craig Ringer,

Risposte:


88

Certamente è. Ne abbiamo discusso in dettaglio sotto questa domanda correlata:

Lo spazio è allocato in multipli di MAXALIGN, che in genere è 8 byte su un sistema operativo a 64 bit o (molto meno comune) 4 byte su un sistema operativo a 32 bit. Se non sei sicuro, controlla pg_controldata. Dipende anche dai tipi di dati delle colonne indicizzate (alcune richiedono il riempimento di allineamento) e dal contenuto effettivo.

Un indice su, diciamo, due integercolonne (4 byte ciascuno) in genere finisce per essere esattamente grande come un indice su uno solo, dove altri 4 byte vengono persi per il riempimento di allineamento.

In tal caso, non esiste davvero un aspetto negativo per il pianificatore di query in cui utilizzare un indice (a,b), rispetto a un indice solo (a). Ed è generalmente preferibile che più query utilizzino lo stesso indice. La possibilità che risieda (o parti di essa) nella cache (veloce) aumenta quando viene condivisa.

Se hai già un indice attivo (a,b), non ha senso creare un altro indice solo (a)se non è sostanzialmente più piccolo. Lo stesso non vale per (b,a)contro (a). Segui il link nella prima riga per ulteriori informazioni al riguardo.

Provenendo dalla direzione opposta, quando hai bisogno di un indice aggiuntivo come quello su (a,b), quindi considera di far cadere un indice esistente solo (a)- se possibile. Spesso non è possibile in quanto è l'indice di un PK o UNIQUEvincolo. Da Postgres 11 potresti invece semplicemente accodare bla definizione del vincolo con la INCLUDEclausola. Dettagli nel manuale.

Oppure crea il nuovo indice su (b,a)invece di coprire le query solo in baggiunta. Per le sole condizioni di uguaglianza, l'ordine delle espressioni dell'indice negli indici btree non ha importanza. Lo fa, tuttavia, quando coinvolge condizioni di portata. Vedere:

Ci sono potenziali svantaggi nell'includere colonne aggiuntive in un indice, anche se questo utilizza solo spazio altrimenti perso per il riempimento di allineamento:

  • Ogni volta che la colonna aggiuntiva viene aggiornata, anche l'indice ha bisogno di un aggiornamento, il che potrebbe aggiungere costi per le operazioni di scrittura e creare un maggiore gonfiamento dell'indice.
  • Gli aggiornamenti HOT (Heap Only Tuple) sulla tabella non sono possibili mentre è coinvolta qualsiasi colonna di indice.

Altre informazioni sugli aggiornamenti HOT:

Come misurare le dimensioni degli oggetti:


1
Potresti estenderlo per dire che, se ho un indice sulla colonna A e sorge la necessità di aggiungere un indice composto (A, B), l'indice A dovrebbe essere eliminato? Se il riutilizzo di un indice migliora l'efficienza della cache e (A, B) ottimizza completamente, A, allora sembra che un indice aggiuntivo su A sprecherebbe spazio e rallenterebbe potenzialmente le cose
jvans

1
@jvans: generalmente vero - con notevoli eccezioni e alternative. Ho aggiunto un paragrafo per affrontarlo.
Erwin Brandstetter,

2

Secondo la tua domanda hai una tabella con i campi A e B. Se la tua domanda è:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

Optimizer sceglierà l'indice composito per evitare Estrai accesso casuale!


-4

È nel caso in cui usi solo il primo nel predicato.

Eseguirà la scansione se si utilizzano le prime colonne di chiave composita e la colonna non chiave di chiave composita.

Per ingannarlo puoi semplicemente dei predicati fittizi come questo e quindi la colonna non chiave:

[A, B] è il tuo indice, [C] - un'altra colonna

Per utilizzare l'indice scrivi come:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... perché seleziona l'indice composito per impostazione predefinita, se è disponibile il singolo indice A?

Utilizzerà l'indice solo nel caso in cui vi siano uno o due predicati [A] o [A], [B]. Non lo utilizzerà nell'ordine [B], [A] o [A], [C]. Per poter utilizzare l'indice con la colonna aggiuntiva [C], è necessario applicare l'indice ordinando i predicati come [A], [B] e [C].


2
Con cosa ottieni esattamente B=B? Penso che tu non ottenga nulla, quindi voterò in assenza di prove che questo non sia semplicemente ignorato dall'ottimizzatore
Jack Douglas,

2
B=Bè effettivamente lo stesso B IS NOT NULL, che sembra non richiesto. Certamente non è necessario usare un indice su (a,b).
Erwin Brandstetter,
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.