2009-06-22 10 views
7

Ipoteticamente, in un database SQL Server, se ho una tabella con due campi int (diciamo una relazione molti-a-molti) che partecipa a join tra altre due tabelle, a quale dimensione approssimativa la tabella diventa abbastanza grande dove il il vantaggio prestazionale degli indici sui due campi int supera il sovraccarico imposto da detti indici?Quando una tabella di database diventa abbastanza grande da rendere un indice utile?

Esistono differenze nell'architettura tra diverse versioni di SQL Server che cambierebbero sostanzialmente questa risposta?

risposta

10

Per le query che riguardano piccole porzioni delle righe della tabella, gli indici sono sempre utili, ci sono 100 righe o 1,000,000.

Vai a questa voce nel mio blog per gli esempi con i piani e particolari prestazioni:

Le query come questo:

SELECT * 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col = t1.col 

sarà molto probabilmente l'uso HASH JOIN. Verrà creata una tabella hash per la tabella più piccola e verranno utilizzate le righe della tabella più grande per sondare la tabella hash.

Per fare ciò, non è necessario alcun indice.

Tuttavia, questa ricerca:

SELECT * 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col = t1.col 
WHERE t1.othercol = @value 

userà NESTED LOOPS: le righe della tabella esterna (table1) viene ricercato utilizzando un indice sulla table1.othercol, e le righe della tabella interna (table2) sarà cercato usando un indice su table2.col.

Se non si dispone di un indice su col1, verrà utilizzato un HASH JOIN che richiede la scansione di tutte le righe da entrambe le tabelle e altre risorse per creare una tabella hash.

indici sono utili anche per le query di questo tipo:

SELECT t2.col 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col = t1.col 

, nel qual caso il motore non ha bisogno di leggere table2 sé a tutti: apparteneva il necessario per questa query può essere trovata nell'indice , che può essere molto più piccolo del tavolo stesso e più efficiente da leggere.

E, naturalmente, se avete bisogno dei vostri dati ordinati e hanno indici su entrambi table1.col e table2.col, quindi la seguente query:

SELECT * 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col = t1.col 
ORDER BY 
     t2.col 

probabilmente utilizzare MERGE JOIN metodo, che è super veloce se entrambi set di righe di input sono ordinati, e il suo output è anche ordinato, il che significa che ORDER BY è gratuito.

Si noti che anche se non si dispone di un indice, un ottimizzatore può scegliere la tabella piccola Eager Spool, che significa creare un indice temporaneo per la durata della query e rilasciare l'indice al termine della query.

Se la query è piccola, sarà molto veloce, ma, di nuovo, un indice non farà male (per le query SELECT intendo). Se l'ottimizzatore non ne ha bisogno, non sarà usato.

Nota, tuttavia, che la creazione di un indice può influire sulle prestazioni di DML, ma è un'altra storia.

+0

In realtà, il database non ordina le chiavi all'interno di una singola pagina. Quindi, fino a quando non andrà oltre questo punto, non ci sarà alcun beneficio. E probabilmente per diverse pagine oltre. – dkretz

+0

@Robert: hanno anche un vantaggio quando si utilizzano solo le colonne indicizzate nella query o quando è necessario ordinare i dati. E no, non sono sempre un vantaggio sulla clausola WHERE, solo su quelli molto selettivi. – Quassnoi

+0

Quassnoi, ho visto il tuo post sul blog. Solo per quello che sai, la decisione finale sull'indicizzazione del nostro database (basata su informazioni aggiuntive a questo post: stackoverflow.com/questions/1033796/...) era di indicizzare tutte le chiavi esterne ECCETTO quelle che partecipano ai join alle tabelle di ricerca contenenti MENO DI 10 Records. –

0

Credo che non appena inizi a partecipare a questi campi int il tuo tavolo sia abbastanza grande. Se la tabella è abbastanza piccola da non trarre vantaggio da un indice, il sovraccarico non sarebbe abbastanza significativo da consentire la disattivazione.

Quando penso al sovraccarico dovuto a un indice, di solito considero la frequenza con cui cambierà l'indice della tabella, tramite inserimenti, eliminazioni e aggiornamenti alle colonne indicizzate.

+0

Gli indici aggiungono il sovraccarico anche sulle istruzioni SELECT, non solo INSERT e UPDATE. –

1

L'indice aumenterà quasi sempre le prestazioni della query, al costo della memoria aggiuntiva e del costo delle prestazioni per inserimento/eliminazione (poiché è necessario mantenere l'indice in quel punto). Il profiling sarà l'unico modo preciso per dire se l'indice, nel tuo caso particolare, è vantaggioso.

In generale, si sta scambiando memoria per la velocità quando si crea un indice (diverso dal costo aggiuntivo di inserimento). Se stai facendo molte domande (selezioni o aggiornamenti) relative al numero di righe inserite/cancellate, gli indici aumenteranno praticamente sempre le tue prestazioni.

+0

Se il caso è relativamente standard (come nell'esempio di due interi in una tabella), il punto di ribaltamento è relativamente di livello, o varierà in funzione del numero di colonne aggiuntive nelle tabelle esterne e di altro sconosciuto fattori? –

+0

L'ottimizzatore sa dove si trova il punto di svolta, quindi non devi preoccuparti di questo. Se la penalità di caricamento è significativa perché stai caricando le righe abbastanza velocemente da notarlo, raggiungerai comunque quel punto in qualsiasi momento. – dkretz

+0

L'indicizzazione accelera le tue domande, quasi a tutto campo. Il numero di colonne farà poca differenza, poiché si tratta di individuare le righe appropriate da restituire (che è in qualche modo separata dal numero di colonne). Se hai pochissimi dati, l'indice potrebbe non essere di grande aiuto, ma è anche quasi gratis - io personalmente indicizzo sempre le colonne che userò frequentemente per qualsiasi query di localizzazione (incluso l'aggiornamento delle righe [purché tu non cambi il colonna indicizzata), dal momento che sarà molto più veloce con un indice, anche in casi relativamente piccoli. –

1

dipende dalla selettività dei dati, se i dati non sono abbastanza selettivi quindi l'indice potrebbe non essere nemmeno utilizzato poiché il costo sarebbe troppo costoso. Se nella tabella sono presenti solo 2 valori e questi valori sono equamente distribuiti, si otterrà una scansione non cercata

Continuo a credere che ogni tabella debba avere una chiave primaria, se si dispone di questo, si dispone già di un indice

+0

È vero che nel mio ipotetico (un join molti-a-molti) le tabelle esterne avrebbero già degli indici. –

+0

Una tabella di giunzione a due colonne? Sarebbe estremamente insolito avere una bassa selettività sulle chiavi primarie da altri due tavoli. – dkretz

+0

@Robert: che dire del tuo tavolo di collegamento? Dovrebbe avere anche una chiave primaria - se non altro, una chiave primaria composta sulle due colonne chiave esterna. In che modo il tuo schema attuale ti protegge dai record duplicati? – GalacticCowboy

1

La penalità per l'inserimento sarà trascurabile fino a molto tempo dopo che verrà visualizzato il beneficio degli indici. L'ottimizzatore è abbastanza intelligente da ignorare comunque gli indici fino a quando non viene cliccato. Quindi basta indicizzare la tabella dall'inizio.

+0

Stai dicendo che SQL Server creerà un piano di esecuzione utilizzando gli indici solo se determina che l'indice fornirà un vantaggio? –

+1

Giusto. Ci sono state diverse domande in SO sul perché gli indici non vengono usati su tavoli di piccole dimensioni, e la risposta è stata "non hai ancora abbastanza dati". – dkretz

+0

Quindi la mia domanda si trasforma in "A quale numero di record esegue SQL Server Optimizer nell'indice?" E la risposta è: "Non importa?" –

1

Un'altra cosa a cui pensare è il concetto di prestazioni di codifica - a volte avere un indice può semplificare il sovraccarico mentale di pensare a come gestire la relazione tra diversi dati. a volte può complicarlo ...

+0

Una cosa che non ho menzionato è che io uso Linq to SQL, che sembra prendere nomi di campi e indici come spunti per ciò che viene incluso nel modello; in particolare, i join di chiavi straniere ottengono una preferenza speciale. –

1

Indipendentemente dalla dimensione, c'è sempre un vantaggio in termini di prestazioni nell'utilizzo di un indice quando si effettua una ricerca.

Per quanto riguarda il sovraccarico, la domanda diventa: quale sovraccarico intendi e come lo rapportano al valore di una ricerca? I due sono valori separati, dopo tutto.

Esistono due tipi di overhead per un indice: spazio (che di solito è trascurabile, a seconda di come è strutturato l'indice) e reindicizza su insert (il server deve ricalcolare un indice dopo ogni inserimento).

Come ho già detto, il problema dello spazio probabilmente non è un grosso problema. Ma la reindicizzazione è. Fortunatamente, è necessario eseguire molte operazioni di inserimento quasi continuo prima che tale forma di sovraccarico diventi un problema.

Quindi linea di fondo: è quasi sempre meglio avere un indice. Inizia da quella posizione e attendi fino a quando la reindicizzazione diventa un collo di bottiglia. Quindi puoi esaminare le alternative.

+0

errato. Crea una tabella con una sola riga, aggiungi un indice e vedi di persona. –

+0

Ok, per "indipendentemente dalla dimensione" intendo "per le tabelle con un conteggio delle righe superiore a 3". Meglio? – Randolpho

+0

Il punto tipover è composto da tre record? Non sembra probabile. –

1

La cosa migliore è lasciare che il server stesso capirlo. Puoi creare un indice nelle colonne in cui ha senso (sono sicuro che ci siano interi capitoli se non libri su come farlo nel modo migliore) e lasciare che il server SQL capisca quando/come usare l'indice.

In molti casi, durante l'ottimizzazione, è necessario leggere i documenti del proprio DBMS per ulteriori informazioni su come utilizza gli indici e collegarlo alle query utilizzate dall'applicazione che si sta ottimizzando. Quindi è possibile perfezionare l'utilizzo dell'indice.

Problemi correlati