A sintaxe do SQL Server para criar um índice em cluster que também é uma chave primária é:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
No que diz respeito ao seu comentário: "fazendo uma PK usar um índice nomeado", o código acima resultará no índice da chave primária chamado "PK_c".
A chave primária e a chave de cluster não precisam ser as mesmas colunas. Você pode defini-los separadamente. No exemplo acima, altere a CLUSTERED
palavra-chave para NONCLUSTERED
e simplesmente adicione um índice em cluster usando a CREATE INDEX
sintaxe:
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);
No SQL Server, o índice clusterizado é a tabela, eles são um e o mesmo. Um índice em cluster define a ordem lógica das linhas armazenadas na tabela. No meu primeiro exemplo, as linhas são armazenadas na ordem dos valores das colunas c1
e c2
. Como a chave de cluster também é definida como a chave primária, a combinação de c1
e c2
deve ser exclusiva em toda a tabela.
No segundo exemplo, a chave primária é composta pelas colunas c1
e c2
, no entanto, a chave de cluster é apenas a c2
coluna. Como não especifiquei o UNIQUE
atributo na CREATE INDEX
instrução, a chave de cluster ( c2
) não precisa ser exclusiva na tabela. Um "uniquificador" será criado automaticamente pelo SQL Server e anexado aos valores na c2
coluna para criar a chave de cluster. Essa chave de cluster, como agora é exclusiva, será usada como um ID de linha em outros índices criados na tabela.
Para provar que a chave de cluster controla o layout das linhas no armazenamento, você pode usar a função não documentada fn_PhysLocCracker(%%PHYSLOC%%)
. O código a seguir mostra as linhas são dispostas em disco na ordem da c2
coluna, que defini como a chave de cluster:
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;
Os resultados do meu tempdb são:
Na imagem acima, as três primeiras colunas são produzidas a partir da fn_PhysLocCracker
função, mostrando a ordem física das linhas no disco. Você pode ver que o slot_id
valor aumenta a etapa de bloqueio com o c2
valor, que é a chave de cluster. O índice de chave primária armazena linhas em uma ordem diferente, o que pode ser visto forçando o SQL Server a retornar resultados da verificação da chave primária:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Observe que não usei uma ORDER BY
cláusula na instrução acima, pois estou tentando mostrar a ordem dos itens no índice de chave primária.
A saída da consulta acima é:
Olhando para a fn_PhysLocCracker
função, podemos ver a ordem física do índice da chave primária.
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;
Como estamos lendo exclusivamente do próprio índice, ou seja, nenhuma coluna fora do índice está sendo referenciada na consulta, os %%PHYSLOC%%
valores representam as páginas no próprio índice.
Os resultados:
create table c (c1 int not null primary key, c2 int)