SQL Server эквивалент предложения Oracle USING INDEX

9

Существует ли SQL Server 2008 эквивалент предложения USING INDEX в Oracle? Специально для конструкции:

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;

В документации Sql Server по уникальным индексам говорится (выделено):

Уникальные индексы реализуются следующими способами:

ПЕРВИЧНЫЙ КЛЮЧ или УНИКАЛЬНОЕ ограничение

При создании ограничения PRIMARY KEY уникальный кластеризованный индекс для столбца или столбцов создается автоматически, если кластеризованный индекс в таблице еще не существует и вы не указываете уникальный некластеризованный индекс . Столбец первичного ключа не может принимать значения NULL.

Что, по-видимому, подразумевает, что существует способ указать, какой индекс следует использовать для первичного ключа.

Nik
источник
Просто определите ПК вместе с таблицей. create table c (c1 int not null primary key, c2 int)
a_horse_with_no_name
Меня интересует именно «заставить PK использовать именованный индекс».
nik
Нет, нет способа сделать это. Первичный ключ - это ограничение и индекс. В том, что вы указали, первичный ключ по умолчанию будет уникальным кластерным индексом. Что сделало бы другой определенный индекс дубликатом, если вы не включили и c1, и c2 в предложение where.
Аарон

Ответы:

7

Существует ли SQL Server 2008 эквивалент предложения USING INDEX в Oracle?

Нет. При создании первичного ключа или уникального ограничения в SQL Server автоматически создается уникальный индекс для поддержки этого ограничения с теми же ключами.

Что, по-видимому, подразумевает, что существует способ указать, какой индекс следует использовать для первичного ключа.

Нет. Документация только пытается объяснить, будет ли автоматический вспомогательный индекс создаваться как кластеризованный или некластеризованный, если вы не укажете. Это смешно сформулировано, я согласен.

Для пояснения, когда вы добавляете ограничение первичного ключа в существующую таблицу без выражения предпочтения, вспомогательный индекс будет кластеризован, если в таблице нет ранее существующего кластеризованного индекса. Поддерживающий индекс будет создан как некластеризованный, если кластерный индекс уже существует

Вы можете специально запросить кластерный или некластерный первичный ключ, используя: PRIMARY KEY CLUSTEREDили PRIMARY KEY NONCLUSTERED.

Справедливости ради, документация намного яснее по этому вопросу:

table_constraint (Transact-SQL)

Пол Уайт 9
источник
5

Синтаксис 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%% значения представляют страницы в самом индексе.

Результаты:

введите описание изображения здесь

Макс Вернон
источник