Indice multicolore e prestazioni


31

Ho una tabella con un indice a più colonne e ho dei dubbi sul corretto ordinamento degli indici per ottenere le massime prestazioni dalle query.

Lo scenario:

  • PostgreSQL 8.4, tabella con circa un milione di righe

  • I valori nella colonna c1 possono avere circa 100 valori diversi . Possiamo presumere che i valori siano distribuiti uniformemente, quindi abbiamo circa 10000 righe per ogni possibile valore.

  • La colonna c2 può avere 1000 valori diversi . Abbiamo 1000 righe per ogni possibile valore.

Durante la ricerca dei dati, la condizione include sempre i valori per queste due colonne, quindi la tabella ha un indice a più colonne che combina c1 e c2. Ho letto dell'importanza di ordinare correttamente le colonne in un indice a più colonne se hai domande che usano solo una colonna per filtrare. Questo non è il caso nel nostro scenario.

La mia domanda è questa:

Dato che uno dei filtri seleziona un set di dati molto più piccolo, potrei migliorare le prestazioni se il primo indice è il più selettivo (quello che consente un set più piccolo)? Non avevo mai preso in considerazione questa domanda fino a quando non ho visto la grafica dell'articolo di riferimento:

inserisci qui la descrizione dell'immagine

Immagine tratta dall'articolo di riferimento sugli indici a più colonne .

Le query utilizzano i valori delle due colonne per il filtraggio. Non ho domande usando solo una colonna per filtrare. Tutti loro sono: WHERE c1=@ParameterA AND c2=@ParameterB. Ci sono anche condizioni come questa:WHERE c1 = "abc" AND c2 LIKE "ab%"

Risposte:


36

Risposta

Dato che ti riferisci al sito web use-the-index-luke.com, considera il capitolo:

Usa l'indice, Luca ›La clausola Where› Ricerca di intervalli › Maggiore, minore e TRA

Ha un esempio che si adatta perfettamente alla tua situazione (indice a due colonne, uno è testato per l' uguaglianza , l'altro per l' intervallo ), spiega (con più di quei bei grafici dell'indice) perché il consiglio di @ ypercube è accurato e lo riassume:

Rule of thumb: index for equality first  then for ranges.

Buono anche per una sola colonna?

Cosa fare per le query su una sola colonna sembra essere chiaro. Maggiori dettagli e parametri di riferimento in merito a tale questione correlata:

Prima la colonna meno selettiva?

A parte questo, cosa succede se si hanno solo le condizioni di uguaglianza per entrambe le colonne ?

Non ha importanza . Metti prima la colonna che ha maggiori probabilità di ricevere condizioni proprie, il che in realtà conta.

Prendi in considerazione questa demo o riproducila tu stesso. Creo una semplice tabella di due colonne con 100k righe. Uno con pochissimi , l'altro con molti valori distinti:

CREATE TEMP TABLE t AS
SELECT (random() * 10000)::int AS lots
     , (random() * 4)::int     AS few
FROM generate_series (1, 100000);

DELETE FROM t WHERE random() > 0.9;  -- create some dead tuples, more "real-life"

ANALYZE t;

SELECT count(distinct lots)   -- 9999
     , count(distinct few)    --    5
FROM   t;

Query:

SELECT *
FROM   t
WHERE  lots = 2345
AND    few = 2;

EXPLAIN ANALYZE output (migliore di 10 per escludere effetti di cache):

Scansione Seq su t (costo = 0,00..5840,84 righe = 2 larghezza = 8)
               (tempo effettivo = 5.646..15.535 righe = 2 anelli = 1)
  Filtro: ((lotti = 2345) E (pochi = 2))
  Buffer: hit locale = 443
Durata totale: 15.557 ms

Aggiungi indice, ripetere il test:

CREATE INDEX t_lf_idx ON t(lots, few);
Scansione indice utilizzando t_lf_idx su t (costo = 0,00..3,76 righe = 2 larghezza = 8)
                                (tempo effettivo = 0,008..0,011 righe = 2 loop = 1)
  Indice cond: ((lotti = 2345) E (pochi = 2))
  Buffer: hit locale = 4
Durata totale: 0,027 ms

Aggiungi altro indice, ripetere il test:

DROP INDEX t_lf_idx;
CREATE INDEX t_fl_idx  ON t(few, lots);
Scansione indice utilizzando t_fl_idx su t (costo = 0,00..3,74 righe = 2 larghezza = 8)
                                (tempo effettivo = 0,007..0,011 righe = 2 loop = 1)
  Indice cond: ((pochi = 2) E (lotti = 2345))
  Buffer: hit locale = 4
Durata totale: 0,027 ms

È anche il caso di 3 (o più) colonne nell'indice?
hayd

@hayd: non sono sicuro di cosa si riferisca a "questo". Potresti fare una nuova domanda . Puoi sempre fare riferimento a questo per contesto. (E lascia un commento qui per tornare indietro.)
Erwin Brandstetter

Con "questo" intendo "è importante l'ordine della definizione dell'indice se ci sono più di 2 colonne nella definizione dell'indice"
hayd

@hayd: il punto più importante: un indice btree è utile per le query con condizioni di uguaglianza sulle principali espressioni di indice. L'ordine tra questi è per lo più irrilevante. Molti altri dettagli che non rientrano in un commento ...
Erwin Brandstetter,

Grazie, proverò a scrivere una domanda coerente e un link ad essa.
hayd

11

Se, come dici tu, le query che coinvolgono queste 2 colonne, sono tutti controlli di uguaglianza di entrambe le colonne, ad esempio:

WHERE c1=@ParameterA AND c2=@ParameterB

non preoccuparti di questo. Dubito che ci sarà alcuna differenza e se ce n'è una, sarà trascurabile. Puoi sempre provare ovviamente, con i tuoi dati e le impostazioni del tuo server. Versioni diverse di un DBMS possono comportarsi in modo leggermente diverso rispetto all'ottimizzazione.

L'ordine all'interno dell'indice importerebbe per altri tipi di query, con controlli di una sola colonna o condizioni di disuguaglianza o condizioni su una colonna e raggruppamento nell'altra, ecc.

Se dovessi scegliere uno dei due ordini, sceglierei di inserire prima la colonna meno selettiva. Considera una tabella con colonne yeare month. È più probabile che tu abbia bisogno di una WHERE year = 2000condizione o a WHERE year BETWEEN 2000 AND 2013o a WHERE (year, month) BETWEEN (1999, 6) AND (2000, 5).

Una query del tipo WHERE month = 7 GROUP BY yearpotrebbe essere certa (Trova persone nate a luglio), ma sarebbe meno frequente. Ciò dipende ovviamente dai dati effettivi memorizzati nella tabella. Scegli un ordine per ora, dì il (c1, c2)e puoi sempre aggiungere un altro indice in seguito (c2, c1).


Aggiornamento, dopo il commento del PO:

Ci sono anche condizioni come questa: WHERE c1 = 'abc' AND c2 LIKE 'ab%'

Questo tipo di query è esattamente una condizione di intervallo sulla c2colonna e richiederebbe un (c1, c2)indice. Se hai anche domande del tipo inverso:

WHERE c2 = 'abc' AND c1 LIKE 'ab%'

allora sarebbe bene se tu avessi anche un (c2, c1)indice.

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.