Дана некоторая таблица с первичным ключом, например:
CREATE TABLE Customers (
CustomerID int NOT NULL PRIMARY KEY,
FirstName nvarchar(50),
LastName nvarchar(50),
Address nvarchar(200),
Email nvarchar(260)
--...
)
у нас есть уникальный первичный ключ CustomerID
.
Традиционно мне могут понадобиться некоторые дополнительные индексы покрытия; например, чтобы быстро найти пользователя с помощью CustomerID
или Email
:
CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
CustomerID,
Email
)
И это те виды индексов, которые я создавал десятилетиями.
Не обязательно быть уникальным, но на самом деле это
Сам индекс существует, чтобы избежать сканирования таблицы; это вспомогательный индекс для повышения производительности (индекс не является ограничением для обеспечения уникальности).
Сегодня я вспомнил немного информации - SQL Server может использовать тот факт, что:
- столбец имеет ограничение внешнего ключа
- столбец имеет уникальный индекс
- ограничение является доверенным
чтобы помочь ему оптимизировать выполнение запроса. Фактически, из Руководства по проектированию индексов SQL Server :
Если данные уникальны и вы хотите обеспечить уникальность, создание уникального индекса вместо неуникального индекса для той же комбинации столбцов предоставляет дополнительную информацию для оптимизатора запросов, которая может создавать более эффективные планы выполнения . В этом случае рекомендуется создание уникального индекса (предпочтительно путем создания уникального ограничения).
Учитывая, что мой многостолбцовый индекс содержит первичный ключ, этот составной индекс будет де-факто уникальным. Это не ограничение, которое мне особенно нужно, чтобы SQL Server применял каждый раз при вставке или обновлении; но дело в том , что это не-кластерный индекс является уникальным.
Есть ли какое-либо преимущество в маркировке этого фактического уникального индекса как уникального?
СОЗДАТЬ УНИКАЛЬНЫЙ ИНДЕКС IX_Customers_CustomerIDEmail ON Клиенты ( Пользовательский ИД, Электронное письмо )
Мне кажется , что SQL Server может быть достаточно умны , чтобы понять , что мой индекс уже является уникальным в силу того , что он содержит первичный ключ.
- Но, возможно, он этого не знает, и для оптимизатора есть преимущество, если я все равно объявлю индекс уникальным.
- За исключением, возможно, это теперь может привести к замедлению во время вставок и обновлений, где он должен выполнять проверки уникальности - там, где раньше это никогда не было раньше.
- Если он не знает, что индекс гарантированно уже будет уникальным, потому что он содержит первичный ключ.
Я не могу найти никаких рекомендаций от Microsoft о том, что делать, если составной индекс содержит первичный ключ.
Преимущества уникальных индексов включают следующее:
- Целостность данных определенных столбцов обеспечивается.
- Предоставляется дополнительная информация, полезная для оптимизатора запросов.
Должен ли я пометить составной индекс как уникальный, если он уже содержит первичный ключ? Или SQL Server может выяснить это для себя?
источник
Ответы:
Возможно нет. Как бы то ни было, оптимизатор в любом случае может использовать информацию об уникальности содержимого ключевого столбца, поэтому реального преимущества нет.
Существует также важное последствие маркировки индекса уникальным в планах обновлений, которые модифицируют ключи этого индекса, чтобы учитывать:
Настроить
План обновления по индексу (неуникальный индекс)
План выполнения:
Оптимизатор часто принимает решение на основе стоимости между обновлением некластеризованных индексов для каждой строки («узкий» план) или для индекса («широкий» план). Стратегия по умолчанию (за исключением таблиц OLTP в памяти) - это широкий план.
Узкие планы (где некластеризованные индексы поддерживаются одновременно с кучей / кластеризованным индексом) являются оптимизацией производительности для небольших обновлений. Эта оптимизация реализована не во всех случаях - использование определенных функций (например, индексированных представлений) означает, что связанные индексы будут поддерживаться в широком плане.
Дополнительная информация: Оптимизация запросов T-SQL, которые изменяют данные
В этом случае я использовал недокументированный флаг трассировки 8790, чтобы вызвать широкий план обновления: поэтому план показывает, что кластеризованные и некластеризованные индексы поддерживаются раздельно.
Разделение превращает каждое обновление в отдельную пару удаления и вставки; Фильтр отфильтровывает любые строки, которые не приведут к изменению индекса.
Дополнительная информация: ( Не обновляет обновления ) командой SQL Server QO.
План обновления по индексу (уникальный индекс)
План выполнения:
Обратите внимание на дополнительные операторы Sort и Collapse, когда индекс помечен как уникальный.
Этот шаблон Split-Sort-Collapse требуется при обновлении ключей уникального индекса, чтобы предотвратить промежуточные нарушения уникального ключа.
Больше информации: Ведение уникальных индексов Крейг Фридман
Сортировка в частности может быть проблемой. Это не только ненужные дополнительные расходы, но и возможные потери на диске, если оценки неточны.
О некластеризованных ключах
Другим фактором, который следует учитывать, является то, что структуры некластеризованного индекса всегда уникальны на каждом уровне индекса, даже если
UNIQUE
он не указан. Ключ (ы) кластеризации - и, возможно, уникальность, если кластерный индекс не помечен как уникальный - добавляются в неуникальный некластеризованный индекс на всех уровнях.Как следствие, следующее определение индекса:
... фактически содержит ключи (Email, CustomerID) на всех уровнях. Поэтому он «доступен» для обеих колонок:
Дополнительная информация: Подробнее о ключах некластеризованного индекса от Kalen Delaney
источник
SQL знает, что он уже уникален (если он включает в себя PK, он не может стать более уникальным), независимо от того, указали ли вы это явно.
Большая разница между неуникальным индексом и уникальным индексом заключается в том, что для неуникальных индексов требуется ключ кластеризованного индекса (со значением uniquifier, если CIX не объявлен как уникальный) на более высоких уровнях индекса, а не только на листе. уровень.
В вашем случае у вас уже есть CIX в ключе, что означает, что он будет уже на каждом уровне индекса.
Но вы можете создать таблицу, которая имеет отдельный PK (уникальный) и CIX (не имеет значения). Затем создайте неуникальный индекс, который включает PK в свой ключ. Поместите в таблицу несколько строк, в том числе несколько легко доступных значений varchar для вашего столбца CIX. Поместите достаточно строк, чтобы вызвать несколько уровней ваших индексов. Затем вы можете использовать DBCC IND, чтобы найти страницы в NCIX, и DBCC PAGE, чтобы открыть некоторые из них, чтобы посмотреть на данные, чтобы увидеть, находятся ли значения ключей CIX на более высоких уровнях.
источник