2009-07-07 7 views
9

Supponiamo di avere una tabella di database con le colonne a, b e c. Ho intenzione di fare interrogazioni su tutte e tre le colonne, ma non sono sicuro di quali colonne in particolare sto interrogando. C'è abbastanza righe della tabella che un indice velocizza enormemente la ricerca, ma si sente sbagliato fare tutte le permutazioni di possibili indici (come questo):Esiste un modo migliore per indicizzare più colonne rispetto alla creazione di un indice per ogni permutazione?

a 
b 
c 
a, b 
a, c 
b, c 
a, b, c 

C'è un modo migliore per gestire questo problema? (È molto probabile che starò bene indicizzando a, b, c da solo, poiché questo ridurrà rapidamente il numero di righe, ma mi chiedo se c'è un modo migliore.)

Se avete bisogno esempi più concreti, nei dati reali, le colonne sono città, stato e codice postale. Inoltre, sto usando un database MySQL.

risposta

19

In MS SQL l'indice "a, b, c" coprirà l'utente per gli scenari "a"; "a, b"; e "a, b, c". Così si avrebbe solo bisogno i seguenti indici:

a, b, c 
b, c 
c 

Non sono sicuro se MySQL funziona allo stesso modo, ma vorrei assumere così.

+7

Questa è la risposta corretta. MySQL funziona allo stesso modo e questa tecnica è chiamata "Leftmost Prefixing". Dal manuale MySQL su http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html: "Se la tabella ha un indice a colonne multiple, il prefisso più a sinistra dell'indice può essere utilizzato da l'ottimizzatore per trovare le righe. Ad esempio, se hai un indice di tre colonne su (col1, col2, col3), hai indicizzato le capacità di ricerca su (col1), (col1, col2) e (col1, col2, col3) . " – zombat

+0

Hmm, avrei dovuto saperlo. ;) Molto impressionante, darò uno scatto. –

+1

Potrebbe anche essere necessario a, c, ma dipende da come appaiono le query.Potrebbe anche essere necessario l'indice individuale per coprire lo scenario OR menzionato da Andriyev, non è sicuro. –

1

Più gli indici vengono creati, più le prestazioni saranno soddisfatte durante le operazioni di aggiornamento e cancellazione. Perché l'indice stesso potrebbe essere aggiornato.

Sì, è possibile utilizzare indici a più colonne. Qualcosa di simile

CREATE TABLE temp (
    id   INT NOT NULL, 
    a   INT NULL, 
    b   INT NULL, 
    c   INT NULL, 
    PRIMARY KEY (id), 
    INDEX ind1 (a,b,c), 
    INDEX ind2 (a,b) 
); 

Questo tipo di indice cioè ind1 sarà sicuramente di aiuto nelle query come

SELECT * FROM temp WHERE a=2 AND b=3 AND c=4; 

Allo stesso modo, IND2 vi aiuterà nelle query come

SELECT * FROM temp WHERE a=2 AND b=3; 

Ma questi indici vinto' essere utilizzato se la query è qualcosa come

SELECT * FROM temp WHERE a=2 OR b=3 OR c=4; 

Qui avrete bisogno di indici separati su a, b, e c.

Quindi, invece di avere così tanti indici, sarei d'accordo con quello che John ha detto cioè avere indici su a, b, c e se ritieni che il tuo carico di lavoro copra più interrogazioni su più colonne, puoi passare agli indici multi-colonna .

applausi

+0

Questa tabella viene raramente aggiornata, quindi non mi interessa se l'aggiornamento è lento. –

1

Dato che le colonne sono in realtà Città, Provincia e CAP, vorrei suggerire solo i seguenti indici:

Index (codice postale)

Se ho ragione, Zip I codici non vengono duplicati in tutti gli Stati Uniti, quindi è inutile aggiungere informazioni sull'indice o sulla città anche perché saranno lo stesso valore per tutti i codici postali. Ad esempio, 90210 è sempre Los Angeles, CA.

INDEX (Città (5)) o INDEX (Città (5)), stato)

Questo è solo un indice sulle prime cinque lettere del nome della città.In molti casi, questo sarà abbastanza specifico che l'indicizzazione State non fornirebbe alcun filtro utile. Ad esempio, "Los A" sarà quasi certamente registrato da Los Angeles, in California. Forse c'è un'altra piccola città negli Stati Uniti che inizia con "Los A", ma ci saranno così pochi record che non vale la pena ingombrare l'indice con i dati di stato. D'altra parte, alcuni nomi di città appaiono in molti stati (viene in mente Springfield), quindi in questi casi è meglio avere anche lo stato indicizzato. Dovrai capire da te quale indice è più adatto al tuo insieme di dati. In caso di dubbio, andrei con il secondo indice (Città e Stato).

INDEX (Stato, sort_field)

Stato è una bella ampio indice (molto probabilmente NY e CA da solo avrà il 30% dei record). Se si prevede la visualizzazione di queste informazioni per l'utente, per esempio, 30 record alla volta, allora si avrebbe una query che termina in

... WHERE STATE = "NY" 
ORDER BY <sort_field> 
LIMIT <number>, 30 

Per rendere che interrogazione efficiente, è necessario includere la colonna di ordinamento nel Indice di stato Quindi, se stai visualizzando le pagine ordinate per Cognome (presumendo che tu abbia quella colonna), allora useresti INDICE (Stato, Cognome (3)), altrimenti MySQL deve ordinare tutti i dei record "NY" prima può darti i 30 che vuoi.

+2

Le tue informazioni sui codici postali non sono strettamente corrette. Molti codici postali hanno più di un "nome di luogo accettabile". Ad esempio, "Hollywood, CA" è un nome di luogo accettabile per 90028, anche se Hollywood è solo un quartiere di Los Angeles e non una città reale. Il "nome del luogo predefinito" per 90028 è in realtà "Los Angeles, CA". Inoltre, a volte due città o porzioni di due città rientrano nello stesso codice postale. È vero che ogni codice ZIP ha esattamente un "nome luogo predefinito", ma non è possibile fare affidamento su quello per i dati inseriti dall'utente. – Geerad

+0

Finché ci sono (nella maggior parte dei casi) non più di due o tre nomi di posto per ciascun codice postale, l'indice andrà comunque bene. –

+0

Non so quali siano le percentuali, ma il mio codice postale ha quattro nomi consentiti. E so di un altro che ha anche quattro. –

1

Dipende dalla query sql.

indice (a, b, c) è diverso da indice (b, c, a) o indice (a, c, b)

4

Per utilizzare indici per tutte le possibili condizioni di uguaglianza su N colonne, è necessario C([N/2], N) indici, cioè N!/([N/2]! * (N - [N/2])!)

si veda questo articolo nel mio blog per le spiegazioni dettagliate:

Si può anche leggere la rigorosa matematica proof dal matematico russo Egor Timoshenko (aggiornamento: ora in inglese).

Si può, tuttavia, ottenere prestazioni decenti con meno indici utilizzando le seguenti tecniche:

Indice fusione

Se le colonne col1, col2 e col3 sono selettivi, allora questa query

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

possono utilizzare tre indici separati su col1, col2 e col3, selezionare il 's ROWID che corrispondono ogni condizione separatamente e li trovano la loro intersezione, come in:

SELECT * 
FROM (
     SELECT rowid 
     FROM mytable 
     WHERE col1 = :value1 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col2 = :value2 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col3 = :value3 
     ) mo 
JOIN mytable mi 
ON  mi.rowid = mo.rowid 

Bitmap indicizzazione

PostgreSQL può costruire indici bitmap temporanei in memoria destra durante la query.

Un indice bitmap è un array di bit contiguo piuttosto compatto.

Ogni bit impostato per l'array indica che il correttore tid deve essere selezionato dalla tabella.

Un tale indice può richiedere ma 128M di memoria temporanea per una tabella con righe 1G.

La query seguente:

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

sarà prima allocare un bitmap zero riempito abbastanza grande per coprire tutte le possibili tid 's nella tabella (che è abbastanza grande per prendere tutti tid' s dal (0, 0) alla ultimo tid, non tenendo conto della mancanza di tid).

Quindi cercherà il primo indice, impostando i bit su 1 se soddisfano la prima condizione.

Quindi eseguirà la scansione del secondo indice, AND 'i bit che soddisfano la seconda condizione con un 1. Questo lascerà 1 solo per quei bit che soddisfano entrambe le condizioni.

Uguale per il terzo indice.

Infine, selezionerà solo le righe con i valori tid corrispondenti ai bit impostati.

Gli oggetti tid verranno recuperati in modo sequenziale, quindi è molto efficiente.

Problemi correlati