Вопрос не в том, «когда ПК должен быть NC», а в том, чтобы спросить «каков правильный ключ для кластерного индекса»?
И ответ действительно зависит от того, как вы запрашиваете данные . Кластерный индекс имеет преимущество перед всеми остальными индексами: поскольку он всегда включает все столбцы, он всегда покрывает. Поэтому запросам, которые могут использовать кластеризованный индекс, безусловно, не нужно использовать поиски для удовлетворения некоторых прогнозируемых столбцов и / или предикатов.
Другая часть загадки - как можно использовать индекс ? Есть три типичных шаблона:
- исследует, когда в индексе ищется одно значение ключа
- сканирование диапазона, когда получен диапазон значений ключа
- упорядочение по требованиям, когда индекс может удовлетворить заказ по требованию остановки и сортировки
Поэтому, если вы проанализируете ожидаемую нагрузку (запросы) и обнаружите, что большое количество запросов будет использовать определенный индекс, поскольку они используют определенный шаблон доступа, который получает выгоду от индекса, имеет смысл предложить этот индекс в качестве кластеризованного индекса.
Еще одним фактором является то, что ключ кластеризованного индекса является ключом поиска, используемым всеми некластеризованными индексами, и поэтому широкий ключ кластеризованного индекса создает волновой эффект и расширяет все некластеризованные индексы, а широкие индексы означают больше страниц, больше ввода-вывода больше памяти, меньше добра.
Хороший кластеризованный индекс стабилен , он не изменяется в течение всего времени существования объекта, поскольку изменение значений ключа кластеризованного индекса означает, что строка должна быть удалена и вставлена обратно.
И хороший кластеризованный индекс растет не в случайном порядке (каждое вновь вставленное значение ключа больше предыдущего значения), чтобы избежать разбиения страницы и фрагментации (без возни с FILLFACTOR
s).
Итак, теперь, когда мы знаем, что такое хороший ключ кластеризованного индекса, соответствует ли первичный ключ (который является логическим свойством моделирования данных) требованиям? Если да, то ПК следует кластеризовать. Если нет, то ПК должен быть некластеризованным.
Для примера рассмотрим таблицу фактов продаж. Каждая запись имеет идентификатор, который является первичным ключом. Но подавляющее большинство запросов запрашивают данные между датой и другой датой, поэтому лучшим ключом кластеризованного индекса будет дата продажи , а не идентификатор . Другим примером наличия кластеризованного индекса, отличного от первичного ключа, является ключ с очень низкой избирательностью, такой как «категория» или «состояние», ключ с очень небольшим количеством различных значений. Наличие ключа кластеризованного индекса с этим ключом низкой селективности в качестве крайнего левого ключа, например (state, id)
, часто имеет смысл из-за сканирования диапазонов, в котором ищутся все записи в определенном «состоянии».
Последнее замечание о возможности некластеризованного первичного ключа в куче (т. Е. Нет кластерного индекса вообще). Это может быть допустимым сценарием, типичной причиной является критическая производительность массовой вставки, поскольку куча имеет значительно лучшую пропускную способность массовой вставки по сравнению с кластерными индексами.
(state, id)
. В этом примере требование «хороший кластерный индекс растет не в случайном порядке» не будет выполнено, не так ли? Так можно ли считать его хорошим кластерным индексом?Основная причина использования кластерных индексов указана в Википедии :
Скажем, у меня есть таблица людей, и у этих людей есть столбец Страна и уникальный первичный ключ. Это таблица демографии, так что это единственное, что меня волнует; какая страна и сколько уникальных людей привязаны к этой стране.
Таким образом, я всегда могу выбрать ГДЕ или ЗАКАЗАТЬ по столбцу Страна; кластерный индекс в первичном ключе не приносит мне никакой пользы, я не обращаюсь к этим данным по PK, я получаю к ним доступ через этот другой столбец. Поскольку у меня может быть только один кластеризованный индекс в таблице, объявление моего PK как кластеризованного помешало бы мне использовать кластеризованный индекс по стране.
Кроме того, здесь хорошая статья на кластерного против некластеризованных индексов , оказывается, кластерные индексы вызвали вставки проблемы производительности в SQL Server 6.5 (который , по крайней мере , надеюсь , это не имеет значения для большинства из нас здесь).
Обратите внимание, что это не так в более поздних версиях.
источник
Если у вас первичный ключ
UNIQUEIDENTIFIER
, убедитесь, что он указанNONCLUSTERED
. Если вы сделаете это кластеризованным, каждая вставка должна будет выполнить кучу перемешивания записей, чтобы вставить новую строку в правильное положение. Это будет производительность танка.источник
UNIQUEIDENTIFIER
тип также существует и имеет такую же вероятность генерирования уникальных ключей, хотя он все еще страдает от размера 128.Очень распространенный пример:
Customer
стол сCustomerID
какCLUSTERED PRIMARY KEY
OrderID (PK), CustomerID, OrderDate
и некоторыми другими столбцамиOrderPositions
с участиемOrderPositionID (PK), OrderId, ProductID, Amount, Price ...
Конечно, «это зависит» - как почти всегда - правильный ответ, но большинство приложений (не BI-отчеты) будут работать на основе клиента (например, вы входите в систему как пользователь 278 на веб-сайт и нажимаете «Мои заказы» или Клерк перечисляет все заказы для клиента 4569, или ваша процедура выставления счетов суммирует все заказы для клиента 137).
В этом случае не имеет смысла кластеризовать таблицу по
OrderID
. Да, у вас будут запросыSELECT ... WHERE OrderId = ?
на перечисление деталей заказа, но обычно это короткий и дешевый (3 чтения) поиск индекса.С другой стороны, если вы будете кластеризовать свою
Order
таблицу с помощьюCustomerID
, ей не нужно будет выполнять многократный поиск ключей каждый раз, когда вы запрашиваете таблицуCustomerId = ?
.Это
CLUSTERED INDEX
должно быть всегдаUNIQUE
, иначе SQL Server добавил бы невидимый (= неиспользуемый) столбец INT,UNIQUIFIER
чтобы обеспечить уникальность, и было бы гораздо разумнее добавлять реальные (пригодные для использования) данные, чем некоторые случайные (в зависимости от порядка вставки) вещи.Поскольку клиент (надеюсь) разместит более одного заказа, нам придется добавить либо
OrderID
(или (если вы обычно сортируете для этого))OrderDate
(если это дата-время - в противном случае клиент будет ограничен одним заказом в день) вCLUSTERED INDEX
и в конечном итоге с:CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)
Те же правила применяются к
OrderPositions
таблице. Обычно большинство запросов будут перечислены все позиции для на определенном порядке, так что вы должны создать ПК с ,OrderPositionID
какNONCLUSTERED
иUNIQUE CLUSTERED INDEX
наOrderId, OrderPositionID
.Кстати, верно, что
Customer
таблица кластеризована по ее PK (CustomerID
потому что она является «таблицей верхнего уровня» и будет - в типичном приложении - в основном запрашиваться ее CustomerID.Таблицы чистого просмотра, например,
Genders
или,InvoiceTypes
илиPaymentType
являются еще одним примером таблиц, которые должны быть сгруппированы по их PK (потому что вы обычно присоединяетесь к нимGenderId
,InvoiceTypeId
илиPaymentTypeId
).источник
Когда кластерный индекс считается более выгодным для всей системы, чем кластеризованный PK, используя некоторую меру производительности. В таблице может быть только один кластерный индекс.
Примерами показателей производительности являются время одного запроса (скорость), интеграция общего времени запросов с таблицей (эффективность) и необходимость добавления множества включаемых столбцов в очень большой некластеризованный индекс для достижения производительности, аналогичной кластерной (размер ).
Это может произойти, когда данные обычно извлекаются с использованием индекса, который не является уникальным, содержит пустые значения (недопустимо в PK), или PK был добавлен по вторичной причине (такой как репликация или идентификация записи журнала аудита).
источник