GUID може да изглежда естествен избор за вашия първичен ключ - и ако наистина трябва, вероятно бихте могли да спорите да го използвате за ПЪРВИЧНИЯ КЛЮЧ на таблицата. Какво силно препоръчвам да не се прави е да използвате колоната GUID като ключ за клъстериране , което SQL Server прави по подразбиране, освен ако изрично не му кажете да не го прави.
Наистина трябва да разграничите два проблема:
-
първичния ключ е логическа конструкция - един от кандидат ключовете, който уникално и надеждно идентифицира всеки ред във вашата таблица. Това може да бъде всичко, наистина -
INT
,GUID
, низ - изберете това, което има най-голям смисъл за вашия сценарий. -
ключът за групиране (колоната или колоните, които дефинират "клъстерирания индекс" в таблицата) - това е физически нещо, свързано със съхранението, и тук най-добрият ви избор е малък, стабилен, непрекъснато нарастващ тип данни -
INT
илиBIGINT
като опция по подразбиране.
По подразбиране първичният ключ в таблица на SQL Server също се използва като ключ за клъстериране - но това не е необходимо да е така! Аз лично видях огромни печалби в производителността при разделянето на предишния основен/клъстериран ключ, базиран на GUID, на два отделни ключа - първичния (логически) ключ на GUID и ключ за групиране (подреждане) на отделен INT IDENTITY(1,1)
колона.
Както Кимбърли Трип - кралицата на индексирането - и други са заявявали много пъти - GUID
тъй като ключът за клъстериране не е оптимален, тъй като поради своята произволност ще доведе до масивна фрагментация на страници и индекси и като цяло до лоша производителност.
Да, знам - има newsequentialid()
в SQL Server 2005 и по-нова версия - но дори това не е наистина и напълно последователно и по този начин също страда от същите проблеми като GUID
- само малко по-слабо.
След това има още един проблем, който трябва да обмислите:ключът за клъстериране на таблица ще бъде добавен към всеки запис във всеки неклъстериран индекс във вашата таблица - по този начин наистина искате да сте сигурни, че е възможно най-малък. Обикновено INT
с 2+ милиарда реда би трябвало да е достатъчно за по-голямата част от таблиците - и в сравнение с GUID
като ключ за клъстериране можете да си спестите стотици мегабайта място за съхранение на диск и в паметта на сървъра.
Бързо изчисление - с помощта на INT
срещу GUID
като първичен и клъстериращ ключ:
- Основна таблица с 1 000 000 реда (3,8 MB срещу 15,26 MB)
- 6 неклъстерирани индекса (22,89 MB срещу 91,55 MB)
ОБЩО:25 MB срещу 106 MB - и това е само на една маса!
Още малко храна за размисъл - отлични неща от Кимбърли Трип - прочетете го, прочетете го отново, усвоете го! Това наистина е евангелието за индексиране на SQL Server.
- GUID като PRIMARY KEY и/или клъстерен ключ
- Дебатът за групирания индекс продължава
- Непрекъснато нарастващ ключ за клъстериране – дебатът за групирания индекс ......... отново!
- Пространството на диска е евтино – това е не въпросът!
PS:разбира се, ако имате работа само с няколкостотин или няколко хиляди реда - повечето от тези аргументи няма да ви окажат особено влияние. Въпреки това:ако влезете в десетките или стотиците хиляди редове или започнете да броите в милиони -тогава тези точки стават много важни и много важни за разбиране.
Актуализация: ако искате да имате вашия PKGUID
колона като първичен ключ (но не и ключ за клъстериране) и друга колона MYINT
(INT IDENTITY
) като ключ за клъстериране - използвайте това:
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)
По принцип:просто трябва да изрично кажете на PRIMARY KEY
ограничение, че е NONCLUSTERED
(в противен случай той се създава като ваш клъстериран индекс по подразбиране) - и след това създавате втори индекс, който е дефиниран като CLUSTERED
Това ще работи - и това е валидна опция, ако имате съществуваща система, която трябва да бъде "препроектирана" за производителност. За нова система, ако започнете от нулата и не сте в сценарий за репликация, винаги бих избирал ID INT IDENTITY(1,1)
като моят клъстериран първичен ключ - много по-ефективен от всичко друго!