Синтаксис SQL Server для создания кластерного индекса, который также является первичным ключом:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
Что касается вашего комментария: «заставить PK использовать именованный индекс», приведенный выше код приведет к тому, что индекс первичного ключа будет назван «PK_c».
Первичный ключ и ключ кластеризации не обязательно должны быть одинаковыми столбцами. Вы можете определить их отдельно. В приведенном выше примере измените CLUSTEREDключевое слово на NONCLUSTERED, а затем просто добавьте кластерный индекс, используяCREATE INDEX синтаксис:
CREATE TABLE dbo.c
(
c1 INT,
c2 INT,
CONSTRAINT PK_c
PRIMARY KEY NONCLUSTERED (c1, c2)
);
CREATE CLUSTERED INDEX CX_c ON dbo.c (c2);
В SQL Server кластеризованный индекс - это таблица, они одно и то же. Кластерный индекс определяет логический порядок строк, хранящихся в таблице. В моем первом примере, строки хранятся в порядке значений c1и c2столбцов. Поскольку ключ кластеризации также определяется как первичный ключ, комбинацияc1 и c2должна быть уникальной для всей таблицы.
Во втором примере, первичный ключ состоит из c1и c2столбцов, однако ключ кластеризации является только c2столбец. Поскольку я не указал UNIQUEатрибут в CREATE INDEXзаявлении, ключ кластеризации (c2 ) не обязательно должен быть уникальным по всей таблице. «Uniquifier» будет автоматически создан SQL Server и добавлен к значениям в c2столбце для создания ключа кластеризации. Этот ключ кластеризации, поскольку он теперь уникален, будет затем использоваться в качестве идентификатора строки в других индексах, созданных в таблице.
Чтобы доказать, что ключ кластеризации контролирует расположение строк в хранилище, вы можете использовать недокументированную функцию fn_PhysLocCracker(%%PHYSLOC%%). Следующий код показывает, что строки располагаются на диске в порядке c2столбца, который я определил как ключ кластеризации:
USE tempdb;
CREATE TABLE dbo.PKTest
(
c1 INT NOT NULL
, c2 INT NOT NULL
, c3 VARCHAR(256) NOT NULL
);
ALTER TABLE PKTest
ADD CONSTRAINT PK_PKTest
PRIMARY KEY NONCLUSTERED (c1, c2);
CREATE CLUSTERED INDEX CX_PKTest
ON dbo.PKTest(c2);
TRUNCATE TABLE dbo.PKTest;
INSERT INTO dbo.PKTest (c1, c2, c3)
SELECT TOP(25) o1.object_id / o2.object_id, o2.object_id, o1.name + '.' + o2.name
FROM sys.objects o1
, sys.objects o2
WHERE o1.object_id >0
and o2.object_id > 0;
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pk.*
FROM dbo.PKTest pk
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Результаты из моей базы данных:

На изображении выше первые три столбца выводятся из fn_PhysLocCrackerфункции, показывая физическое упорядочение строк на диске. Вы можете видеть, что slot_idзначение увеличивает шаг блокировки со c2значением, которое является ключом кластеризации. Индекс первичного ключа хранит строки в другом порядке, что можно увидеть, заставив SQL Server возвращать результаты сканирования первичного ключа:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Обратите внимание, я не использовал ORDER BY предложение в приведенном выше утверждении, так как я пытаюсь показать порядок элементов в индексе первичного ключа.
Выходные данные из вышеприведенного запроса:

Что касается fn_PhysLocCrackerфункции, мы можем видеть физический порядок индекса первичного ключа.
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN)
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Поскольку мы читаем исключительно из самого индекса, то есть в запросе нет ссылок на столбцы вне индекса, %%PHYSLOC%% значения представляют страницы в самом индексе.
Результаты:

create table c (c1 int not null primary key, c2 int)