SQL Server equivalente a la cláusula Oracle USING INDEX

9

¿Existe un equivalente de SQL Server 2008 de la cláusula USING INDEX en Oracle? Específicamente para la construcción:

CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX ci ON c (c1, c2);
ALTER TABLE c ADD CONSTRAINT cpk PRIMARY KEY (c1) USING INDEX ci;

En la Documentación del servidor SQL sobre índices únicos, se indica (énfasis agregado):

Los índices únicos se implementan de las siguientes maneras:

CLAVE PRIMARIA o restricción ÚNICA

Cuando crea una restricción PRIMARY KEY, un índice agrupado único en la columna o columnas se crea automáticamente si un índice agrupado en la tabla aún no existe y no especifica un índice no agrupado único . La columna de clave principal no puede permitir valores NULL.

Lo que parece implicar que hay una manera de especificar qué índice debe usarse para una Clave primaria.

nik
fuente
Simplemente defina el PK junto con la tabla. create table c (c1 int not null primary key, c2 int)
a_horse_with_no_name
Es el "hacer un uso PK un índice llamado" parte que estoy interesado.
nik
No, no hay forma de hacerlo. Una clave primaria es una restricción y un índice. En lo que ha proporcionado, la clave principal sería, por defecto, un índice agrupado único. Lo que haría que el otro índice definido sea un duplicado a menos que haya incluido tanto c1 como c2 en la cláusula where.
Aaron

Respuestas:

7

¿Existe un equivalente de SQL Server 2008 de la cláusula USING INDEX en Oracle?

No. Cuando crea una clave primaria o una restricción única en SQL Server, se crea automáticamente un índice único para admitir esa restricción, con las mismas claves.

Lo que parece implicar que hay una manera de especificar qué índice debe usarse para una Clave primaria.

No. La documentación solo intenta explicar si el índice de soporte automático se creará como agrupado o no agrupado, si no lo especifica. Está redactado de manera confusa, estoy de acuerdo.

Para aclarar, cuando agrega una restricción de clave principal a una tabla existente sin expresar una preferencia, el índice de soporte se agrupará si no hay un índice agrupado preexistente en la tabla. El índice de soporte se creará como no agrupado si ya hay un índice agrupado

Puede solicitar específicamente una clave primaria agrupada o no agrupada utilizando: PRIMARY KEY CLUSTEREDo PRIMARY KEY NONCLUSTERED.

Para ser justos, la documentación es mucho más clara sobre el tema en:

table_constraint (Transact-SQL)

Paul White 9
fuente
5

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 CLUSTEREDpalabra clave a NONCLUSTERED, y luego simplemente agregue un índice agrupado utilizando la CREATE INDEXsintaxis:

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 c1y c2. Dado que la clave de agrupación también se define como la clave principal, la combinación de c1y c2debe ser única en toda la tabla.

En el segundo ejemplo, la clave primaria se compone de las columnas c1y c2, sin embargo, la clave de agrupación es solo la c2columna. Como no especifiqué el UNIQUEatributo en la CREATE INDEXdeclaración, c2no 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 c2columna 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 c2columna, 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:

ingrese la descripción de la imagen aquí

En la imagen de arriba, las tres primeras columnas salen de la fn_PhysLocCrackerfunción, mostrando el orden físico de las filas en el disco. Puede ver que el slot_idvalor aumenta el paso de bloqueo con el c2valor, 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 BYclá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:

ingrese la descripción de la imagen aquí

Mirando a la fn_PhysLocCrackerfunció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:

ingrese la descripción de la imagen aquí

Max Vernon
fuente