Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Quali sono le procedure consigliate per l'utilizzo di un GUID come chiave primaria, in particolare per quanto riguarda le prestazioni?

I GUID possono sembrare una scelta naturale per la tua chiave primaria e, se proprio devi, potresti probabilmente obiettare di usarla per la CHIAVE PRIMARIA della tabella. Cosa consiglio vivamente di non fare è utilizzare la colonna GUID come chiave di cluster , operazione che SQL Server esegue per impostazione predefinita, a meno che tu non specifichi espressamente di non farlo.

Devi davvero tenere separati due problemi:

  1. la chiave primaria è un costrutto logico, una delle chiavi candidate che identifica in modo univoco e affidabile ogni riga della tabella. Può essere qualsiasi cosa, davvero:un INT , un GUID , una stringa:scegli ciò che ha più senso per il tuo scenario.

  2. la chiave di raggruppamento (la colonna o le colonne che definiscono l'"indice cluster" nella tabella) - questo è un fisico cosa relativa allo storage, e qui, un tipo di dati piccolo, stabile e in continua crescita è la scelta migliore - INT o BIGINT come opzione predefinita.

Per impostazione predefinita, la chiave primaria su una tabella di SQL Server viene utilizzata anche come chiave di clustering, ma non è necessario che sia così! Personalmente ho riscontrato enormi miglioramenti delle prestazioni suddividendo la precedente chiave primaria/cluster basata su GUID in due chiavi separate:la chiave primaria (logica) sul GUID e la chiave di clustering (ordinamento) su un INT IDENTITY(1,1) colonna.

Come Kimberly Tripp - la regina dell'indicizzazione - e altri hanno affermato molte volte - un GUID poiché la chiave di clustering non è ottimale, poiché a causa della sua casualità, porterà a un'enorme frammentazione di pagine e indici e a prestazioni generalmente scadenti.

Sì, lo so:c'è newsequentialid() in SQL Server 2005 e versioni successive, ma anche quello non è veramente e completamente sequenziale e quindi soffre degli stessi problemi del GUID - solo un po' meno prominente.

Poi c'è un altro problema da considerare:la chiave di clustering su una tabella verrà aggiunta a ogni voce di ogni indice non cluster sulla tabella, quindi vuoi davvero assicurarti che sia il più piccolo possibile. Tipicamente, un INT con oltre 2 miliardi di righe dovrebbe essere sufficiente per la stragrande maggioranza delle tabelle e rispetto a un GUID come chiave di clustering, puoi risparmiare centinaia di megabyte di spazio di archiviazione su disco e nella memoria del server.

Calcolo rapido - utilizzando INT rispetto a GUID come chiave primaria e di clustering:

  • Tabella di base con 1'000'000 di righe (3,8 MB contro 15,26 MB)
  • 6 indici non cluster (22,89 MB contro 91,55 MB)

TOTALE:25 MB contro 106 MB - e questo è solo su un unico tavolo!

Qualche altro spunto di riflessione - materiale eccellente di Kimberly Tripp - leggilo, rileggilo, digeriscilo! È davvero il vangelo dell'indicizzazione di SQL Server.

  • GUID come CHIAVE PRIMARIA e/o chiave cluster
  • Il dibattito sugli indici a grappolo continua
  • Chiave di clustering in costante aumento:il dibattito sull'indice cluster..........di nuovo!
  • Lo spazio su disco è poco, non il punto!

PS:ovviamente, se hai a che fare solo con poche centinaia o poche migliaia di righe, la maggior parte di questi argomenti non avrà molto impatto su di te. Tuttavia:se entri nelle decine o centinaia di migliaia di righe, o inizi a contare milioni - allora questi punti diventano molto cruciali e molto importanti da comprendere.

Aggiornamento: se vuoi avere il tuo PKGUID colonna come chiave primaria (ma non chiave di clustering) e un'altra colonna MYINT (INT IDENTITY ) come chiave di clustering:utilizza questo:

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

Fondamentalmente:devi solo esplicitamente indica la PRIMARY KEY vincolo che sia NONCLUSTERED (altrimenti viene creato come indice cluster, per impostazione predefinita) - quindi crei un secondo indice definito come CLUSTERED

Funzionerà ed è un'opzione valida se si dispone di un sistema esistente che deve essere "re-ingegnerizzato" per le prestazioni. Per un nuovo sistema, se inizi da zero e non ti trovi in ​​uno scenario di replica, sceglierei sempre ID INT IDENTITY(1,1) come chiave primaria in cluster, molto più efficiente di qualsiasi altra cosa!