Regola hard e fast per includere colonne nell'indice


38

Esiste una regola rigida e rapida per decidere quali colonne e in quale ordine devono essere inserite Incluso nell'indice non cluster. Stavo solo leggendo questo post https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index e l'ho trovato per la seguente query:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Il poster ha suggerito di creare un indice in questo modo:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

ecco la mia domanda: perché non possiamo fare un indice come questo

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

o

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

e quale cosa induce il poster a decidere di mantenere inclusa la colonna LastName. Perché non altre colonne? e come decidere in quale ordine dovremmo tenere le colonne lì?


3
INCLUDE dovrebbe normalmente avere i campi di cui avrai bisogno DOPO che è stato trovato un record, salvandoti un viaggio di andata e ritorno per ottenere più dati. L'ordine dei campi in INCLUDE non è importante.
Jimbo,

Ryk, personalmente trovo utile questo post.
Jason Young,

Trovo utile anche questa domanda. Concentriamoci su buone domande e buone risposte invece di stalking individui ....
Volvox

Risposte:


47

Quel suggerimento dell'indice di marc_s è sbagliato. Ho aggiunto un commento (Ed è stata accettata anche la mia risposta!)

L'indice per questa query sarebbe

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Un indice è in genere

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Dove:

  • KeyColList = Colonne chiave = utilizzato per la limitazione e l'elaborazione delle righe
    DOVE, UNISCITI, ORDINA PER, Raggruppa per ecc
  • NonKeyColList = Colonne non chiave = utilizzato in SELECT e aggregazione (ad es. SUM (col)) dopo selezione / limitazione

+1 - Sono d'accordo (vedi il mio ans) che gli indici di esempio in OP sono inutili per la query!
JNK

Grande! solo un'altra cosa che deciderà l'ordine di KeyColList e NonKeyColList. Puoi spiegare con il mio esempio? Supponiamo ora che la mia query sia SELECT EmployeeID, DepartmentID, Last FROM FROM EmployeeWHERE DepartmentID = 5, StateID = 4 Come dovrebbe essere l'indice ora?

@ Rocky - l' NonKeyColListordine non ha importanza. KeyColListl'ordine dovrebbe essere in ordine di frequenza che prevedi vengano utilizzati nelle query. Vedi i miei appunti sulla mia risposta qui sotto, ma è come Last Name, First Name, Middile Initialin una rubrica. È necessario il primo campo per trovare il secondo campo.
JNK,

@gbn Abbiamo davvero richiesto EmployeeID nell'elenco di inclusioni? Come se avessimo un indice cluster sulla colonna EmployeeID e soprattutto se creiamo un indice non cluster sulla colonna DeptId, quindi l'indice non cluster fa già riferimento alla chiave di cluster che è inclusa nella struttura dell'indice non cluster, inclusa la chiave di cluster nell'elenco INCLUDE non ' aggiungere eventuali vantaggi.
Viswanathan Iyer,

1
@ViswanathanIyer non verrà aggiunto due volte all'effettivo spazio di archiviazione su disco: SQL Server lo rileva. Quindi non è necessario ma rende le cose più chiare. Tuttavia, non conosciamo alcun indice cluster nella domanda, quindi è più sicuro assumerne nessuno.
gbn

19

JNK e gbn hanno dato ottime risposte, ma vale anche la pena considerare il quadro generale, non solo concentrarsi su una singola query. Sebbene questa particolare query possa beneficiare di un indice (n. 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Questo indice non aiuta affatto se la query cambia leggermente, come ad esempio:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Ciò richiederebbe l'indice (n. 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Immagina di avere 1.000 dipendenti nel Dipartimento 5. Usando l'indice n. 1, per trovare tutti gli Smith, dovresti cercare tutte le 1.000 righe del Dipartimento 5, poiché le colonne incluse non fanno parte della chiave. Usando l'indice n. 2, puoi cercare direttamente al Dipartimento 5, LastName Smith.

L'Indice n. 2 è quindi più utile per servire una gamma più ampia di query, ma il costo è una chiave di indice più gonfia, che ingrandirà le pagine non foglia dell'indice. Ogni sistema sarà diverso, quindi non esiste una regola empirica qui.


Come nota a margine, vale la pena sottolineare che se EmployeeID era la chiave di clustering per questa tabella - presupponendo un indice cluster - quindi non è necessario includere EmployeeID - è presente in tutti gli indici non cluster, il che significa che l'indice n. 2 potrebbe semplicemente essere

Employee(DepartmentID, LastName)

2
+1 per ulteriori informazioni utili. Per il tuo ultimo punto, ho testato questo e l'uso esplicito di EmployeeID in INCLUDE è effettivamente ignorato (in base alla dimensione dell'indice) se EmployeeID è l'indice cluster. È più ovvio anche se penso e non c'è spazio negativo.
gbn

1
Sono assolutamente d'accordo: è sempre meglio essere espliciti, soprattutto se non costa nulla!

1
Nel caso ... Voglio dire, ho testato la chiave cluster in INCLUDE (non EmployeeID esplicitamente) e non aggiunge spazio. Nelle colonne chiave lo fa.
gbn

@gbn Sì, la chiave del cluster deve risiedere solo a livello foglia dell'indice, che è dove risiedono le colonne INCLUDE. Spostarlo nella chiave di indice significherebbe che esisterebbe anche nelle pagine non foglia. Ciò comporterebbe un po 'di gonfiore, ma non una quantità terribile (nelle pagine di livello intermedio, aggiungerei altri 4 byte per pagina a livello di foglia, assumendo un numero intero).

Questa è un'ottima risposta che include alcuni degli effetti descritti in questo articolo: sqlperformance.com/2014/07/sql-indexes/… Se la tua query cambia, allora fai anche i requisiti dei tuoi indici. Potresti stare meglio con la risposta di Jim, ma potresti andare meglio con la risposta di @gbn.
John aka hot2use,

7

Non sono sicuro di come l'hai preso per primo. Per me, per quella query, vorrei usare:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

Non esiste una "regola rigida" per praticamente qualsiasi cosa in SQL.

Ma, per il tuo esempio, l'unico campo che verrà utilizzato dall'indice è DepartmentIDperché è nella WHEREclausola.

Gli altri campi devono solo essere facilmente accessibili da lì. Si seleziona in base a DepartmentIDquindi INCLUDEha quei campi nel nodo foglia dell'indice.

Non vuoi usare altri tuoi esempi perché non funzionerebbero per questo indice.

Pensa a un indice come a una rubrica. La maggior parte delle rubriche telefoniche sono ordinate per cognome, nome, medio iniziale. Se conosci il nome di qualcuno, ma non il suo cognome, la rubrica non ti serve perché non puoi cercare il nome in base all'ordine dell'indice della rubrica.

I INCLUDEcampi sono come il numero di telefono, l'indirizzo, ecc. Altre informazioni per ogni voce nel libro.

MODIFICARE:

Per chiarire ulteriormente perché non utilizzare:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Questo indice è utile solo se hai uno EmployeeIDo entrambi EmployeeID e LastNamenella tua WHEREclausola. Questo è praticamente l' OPPOSITO di ciò di cui hai bisogno per questa query.


@ajbeaven è vero, ecco perché il commento che ho inserito nella modifica dice che hai bisogno di OGNI ID impiegato o di entrambe le colonne.
JNK,

durante dispiace frainteso :(
ajbeaven

0

Penso che potresti essere ancora in grado di utilizzare l'indice (employee_id, department_id), ma dovresti includere una riga 'fittizia' nella frase where, come: "employee_id = employee_id)

  • avendo un indice su (employee_id, departemnent_id),
  • dover cercare / limitare solo su un ID_gruppo
  • sapendo che non utilizzerà l'indice poiché l'ordine sbagliato (o le cose sono cambiate ormai, e il seguente "trucco" non è più necessario. Sono un "vecchio"?) .
  • Usa il "vecchio" tricK?

    seleziona * da Employee emp
    dove emp.employee_id = emp.employee_id
    e emp.department_id = 5

(Quindi non mi sto concentrando sulla parte di inclusione qui di Cognome, ma sul sì / o non essere utilizzato della chiave.)

Cordiali saluti,

Miguell


2
No, è inutile e non efficiente.
ypercubeᵀᴹ

In particolare, dovrà comunque eseguire una scansione dell'indice per cercare tutti gli ID dei dipendenti per trovare tutte le istanze di department_id 5. Se ci sono 1000 dipendenti e 5 dipartimenti, SQL deve esaminare tutti i 1000 dipendenti per trovare tutte le righe per un determinato reparto.
Mark Sowul,

Consideriamo ora il caso opposto (l'indice è su department_id, employee_id). Ovviamente è facile trovare un determinato reparto ora, ma nota anche che per trovare un determinato dipendente, SQL deve solo scansionare 5 dipartimenti per trovare tutte le righe per un determinato dipendente.
Mark Sowul,
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.