La sintaxis de SQL Server para crear un índice agrupado que también es una clave principal es:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
En cuanto a su comentario: "hacer que un PK use un índice con nombre", el código anterior dará como resultado que el índice de clave principal se llame "PK_c".
La clave principal y la clave de agrupación no tienen que ser las mismas columnas. Puede definirlos por separado. En el ejemplo anterior, cambie la CLUSTERED
palabra clave a NONCLUSTERED
, y luego simplemente agregue un índice agrupado utilizando la CREATE INDEX
sintaxis:
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);
En SQL Server, el índice agrupado es la tabla, son uno y el mismo. Un índice agrupado define el orden lógico de las filas almacenadas en la tabla. En mi primer ejemplo, las filas se almacenan en el orden de los valores de las columnas c1
y c2
. Dado que la clave de agrupación también se define como la clave principal, la combinación de c1
y c2
debe ser única en toda la tabla.
En el segundo ejemplo, la clave primaria se compone de las columnas c1
y c2
, sin embargo, la clave de agrupación es solo la c2
columna. Como no especifiqué el UNIQUE
atributo en la CREATE INDEX
declaración, c2
no es necesario que la clave de agrupación ( ) sea única en toda la tabla. SQL Server creará automáticamente un "uniquifier" y se agregará a los valores de la c2
columna para crear la clave de agrupación. Esta clave de agrupación, dado que ahora es única, se utilizará como una identificación de fila en otros índices creados en la tabla.
Con el fin de demostrar la agrupación controles clave la disposición de filas de almacenamiento, puede utilizar la función de indocumentado, fn_PhysLocCracker(%%PHYSLOC%%)
. El siguiente código muestra que las filas se presentan en el disco en el orden de la c2
columna, que he definido como la clave de agrupación:
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;
Los resultados de mi tempdb son:
En la imagen de arriba, las tres primeras columnas salen de la fn_PhysLocCracker
función, mostrando el orden físico de las filas en el disco. Puede ver que el slot_id
valor aumenta el paso de bloqueo con el c2
valor, que es la clave de agrupación. El índice de la clave primaria almacena las filas en un orden diferente, lo que se puede ver al forzar a SQL Server a devolver resultados al escanear la clave primaria:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Tenga en cuenta que no utilicé una ORDER BY
cláusula en la declaración anterior, ya que intento mostrar el orden de los elementos en el índice de clave principal.
El resultado de la consulta anterior es:
Mirando a la fn_PhysLocCracker
función, podemos ver el orden físico del índice de la clave primaria.
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;
Dado que estamos leyendo exclusivamente del índice en sí, es decir, no se hace referencia a columnas fuera del índice en la consulta, los %%PHYSLOC%%
valores representan las páginas en el índice en sí.
Los resultados:
create table c (c1 int not null primary key, c2 int)