Devo contrassegnare un indice composito come univoco se contiene la chiave primaria?


9

Data una tabella con una chiave primaria, ad esempio:

CREATE TABLE Customers (
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   Address nvarchar(200),
   Email nvarchar(260)
   --...
)

abbiamo una chiave primaria univoca attivata CustomerID.

Tradizionalmente potrei aver bisogno di alcuni indici di copertura aggiuntivi; ad esempio per trovare rapidamente un utente tramite uno CustomerIDo Email:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)

E questi sono i tipi di indici che ho creato per decenni.

Non è necessario per essere unico, ma in realtà lo è

L'indice stesso esiste per evitare una scansione della tabella; è un indice di copertura al fine di favorire le prestazioni (l'indice non è presente come un vincolo per rafforzare l'unicità).

Oggi ho ricordato un po 'di informazioni: SQL Server può usare il fatto che:

  • una colonna ha un vincolo di chiave esterna
  • una colonna ha un indice univoco
  • un vincolo è attendibile

per aiutarlo a ottimizzare l'esecuzione della query. In effetti, dalla Guida alla progettazione dell'indice di SQL Server :

Se i dati sono univoci e si desidera applicare l'univocità, la creazione di un indice univoco anziché un indice non univoco sulla stessa combinazione di colonne fornisce ulteriori informazioni per Query Optimizer in grado di produrre piani di esecuzione più efficienti . In questo caso è consigliabile creare un indice univoco (preferibilmente creando un vincolo UNIQUE).

Dato che il mio indice multi-colonna contiene la chiave primaria, questo indice composito sarà di fatto univoco. Non è un vincolo che ho particolarmente bisogno di far applicare SQL Server durante ogni inserimento o aggiornamento; ma il fatto è che questo indice non cluster è unico.

C'è qualche vantaggio nel contrassegnare questo indice unico di fatto come realmente unico?

CREA UN INDICE UNICO IX_Customers_CustomerIDEmail SU Clienti
(
   Identificativo del cliente,
   E-mail
)

Mi sembra che SQL Server possa essere abbastanza intelligente da rendermi conto che il mio indice è già unico in quanto contiene la chiave primaria.

  • Ma forse non lo sa, e c'è un vantaggio per l'ottimizzatore se dichiaro comunque l'indice come unico.
  • Tranne forse ciò potrebbe ora portare a rallentamenti durante inserimenti e aggiornamenti, dove deve eseguire controlli di unicità - dove prima non aveva mai dovuto prima.
  • A meno che non sappia che l'indice è già garantito come unico, poiché contiene la chiave primaria.

Non riesco a trovare alcuna guida da Microsoft su cosa fare quando un indice composito contiene la chiave primaria.

I vantaggi di indici univoci includono:

  • L'integrità dei dati delle colonne definite è garantita.
  • Vengono fornite ulteriori informazioni utili per Query Optimizer.

Devo contrassegnare un indice composito come unico se contiene già la chiave primaria? O SQL Server può capirlo da solo?


4
Per trovare rapidamente un cliente tramite CustomerID, probabilmente il PK è sufficiente. Per trovare un cliente via e-mail, preferirei avere il secondo indice solo sull'e-mail (copre già la chiave di clustering). Ad ogni modo, so che questo è fittizio, ma sì, lo contrassegnerei come unico se sai che deve essere unico, quel vincolo probabilmente non può danneggiare gli inserti abbastanza da compensare i casi in cui può aiutare l'ottimizzatore. Ma tutto dipende dal tuo carico di lavoro, su cui dovremmo speculare ...
Aaron Bertrand

1
Ne abbiamo discusso a lungo qui. E mentre non riusciamo a pensare a un modo per ottenere dati per dimostrarlo in un modo o nell'altro, supponiamo che i ragazzi di SQL Server siano probabilmente molto intelligenti e l'ottimizzatore probabilmente è già in grado di effettuare questa meta ottimizzazione. Immaginiamo anche che probabilmente è meglio che l'indice comunichi l' intento - che è semplicemente un indice, e non imporre un'unicità come regola aziendale quando altrimenti verrebbe fatto solo per provare a indovinare le capacità di SQL Server.
Ian Boyd,

Risposte:


11

Devo contrassegnare un indice composito come univoco se contiene già la chiave primaria?

Probabilmente no. L'ottimizzatore in genere può comunque utilizzare le informazioni sull'unicità della colonna chiave contenuta, quindi non c'è alcun vantaggio reale.

Vi è anche un'importante conseguenza della marcatura di un indice univoco nei piani di aggiornamento che modificano le chiavi di tale indice da considerare:

Impostare

CREATE TABLE dbo.Customers 
(
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   [Address] nvarchar(200),
   Email nvarchar(260)
);

CREATE NONCLUSTERED INDEX 
    IX_Customers_CustomerIDEmail 
ON dbo.Customers
(
   CustomerID,
   Email
);

-- Pretend we have some rows
UPDATE STATISTICS dbo.Customers 
WITH ROWCOUNT = 100000, PAGECOUNT = 20000;

Piano di aggiornamento per indice (indice non univoco)

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Progetto esecutivo:

Dividi e filtra

L'ottimizzatore spesso prende una decisione basata sui costi tra l'aggiornamento di indici non cluster per riga (un piano "ristretto") o per indice (un piano "ampio"). La strategia predefinita (ad eccezione delle tabelle OLTP in memoria) è un piano ampio.

I piani stretti (in cui gli indici non cluster vengono gestiti contemporaneamente all'indice heap / cluster) sono un'ottimizzazione delle prestazioni per piccoli aggiornamenti. Questa ottimizzazione non è implementata per tutti i casi: l'utilizzo di determinate funzionalità (come le viste indicizzate) significa che gli indici associati verranno mantenuti in un ampio piano.

Ulteriori informazioni: Ottimizzazione delle query T-SQL che modificano i dati

In questo caso, ho usato il flag di traccia non documentato 8790 per forzare un piano di aggiornamento ampio: il piano mostra quindi che gli indici cluster e non cluster vengono gestiti separatamente.

La divisione trasforma ogni aggiornamento in una coppia separata di eliminazione e inserimento; il filtro filtra qualsiasi riga che non comporterebbe una modifica all'indice.

Ulteriori informazioni: ( Aggiornamenti senza aggiornamento ) da parte del team QO di SQL Server.

Piano di aggiornamento per indice (indice univoco)

-- Same index, but unique
CREATE UNIQUE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)
WITH (DROP_EXISTING = ON);

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Progetto esecutivo:

Split-Sort-Collapse

Notare gli operatori di ordinamento e compressione aggiuntivi quando l'indice è contrassegnato come univoco.

Questo modello Split-Sort-Collapse è necessario quando si aggiornano le chiavi di un indice univoco, per evitare violazioni intermedie delle chiavi univoche.

Ulteriori informazioni: Mantenimento di indici unici di Craig Freedman

L'ordinamento in particolare può essere un problema. Non è solo un costo aggiuntivo non necessario, ma potrebbe non essere disponibile su disco se le stime non sono accurate.

Informazioni sulle chiavi non cluster

Un altro fattore da considerare è che le strutture di indice non cluster sono sempre uniche, a tutti i livelli dell'indice, anche se UNIQUEnon specificato. Le chiavi del cluster - e possibilmente un unificatore se l'indice del cluster non è contrassegnato come univoco - vengono aggiunti a un indice non cluster non univoco a tutti i livelli.

Di conseguenza, il seguente indice definiton:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   Email
)
WITH (DROP_EXISTING = ON);

... contiene effettivamente le chiavi (Email, CustomerID) a tutti i livelli. È quindi "ricercabile" su entrambe le colonne:

SELECT * 
FROM dbo.Customers AS C WITH (INDEX(IX_Customers_CustomerIDEmail))
WHERE C.Email = N'Email'
AND C.CustomerID = 1;

cerca

Ulteriori informazioni: Ulteriori informazioni sulle chiavi di indice non cluster di Kalen Delaney


8

SQL sa già che è unico (se include il PK, non può essere più unico), indipendentemente dal fatto che lo dica esplicitamente.

La grande differenza tra un indice non univoco e un indice univoco è che gli indici non univoci richiedono la chiave di indice cluster (con valore unificatore se il CIX non è dichiarato come univoco) ai livelli più alti dell'indice, non solo alla foglia livello.

Nel tuo caso, hai già il CIX nella chiave, il che significa che sarà già a tutti i livelli dell'indice.

Ma potresti creare una tabella che ha un PK separato (unico) e CIX (non importa). Quindi creare un indice non univoco che includa il PK nella sua chiave. Inserisci alcune righe nella tabella, inclusi alcuni valori varchar facilmente reperibili per la tua colonna CIX. Inserisci abbastanza righe per causare più livelli degli indici. Quindi è possibile utilizzare DBCC IND per trovare le pagine nel proprio NCIX e DBCC PAGE per aprirne alcune per esaminare i dati, per vedere se i valori della chiave CIX sono ai livelli più alti.

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.