Должны ли кластерные индексы быть уникальными?

84

Что произойдет, если кластеризованный индекс не уникален? Может ли это привести к снижению производительности из-за того, что вставленные строки перетекают на страницу «переполнения»?

"Сделано" ли оно уникальным, и если да, то как? Как лучше всего сделать его уникальным?

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

Благодаря!

LittleGreen
источник

Ответы:

92

Они не обязательно должны быть уникальными, но это, безусловно, приветствуется.
Я еще не встречал сценария, в котором я хотел бы создать CI для неуникального столбца.

Что произойдет, если вы создадите CI для неуникального столбца

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

Приводит ли это к плохой работе?

Добавление уникальности, безусловно, увеличивает накладные расходы на его вычисление и сохранение.
Если эти накладные расходы будут заметными, зависит от нескольких факторов.

  • Сколько данных содержит таблица.
  • Какая скорость вставок.
  • Как часто CI используется в выборке (когда индексы покрытия не существуют, почти всегда).

Редактировать,
как было указано Ремусом в комментариях, существуют варианты использования, когда создание неуникального CI было бы разумным выбором. То, что я не встречал ни одного из этих сценариев, просто показывает мою нехватку осведомленности или компетентности (выберите ваш выбор).

Ливен Кеерсмэкерс
источник
31
+1 потому что все, что вы говорите, правильно, но просто хотел добавить: неуникальные CI довольно распространены, когда сканирование диапазона в конкретном (неуникальном) столбце является распространенным шаблоном доступа.
Ремус Русану
@Remus Ruşanu: Я был думать о добавлении заявления об отказе к моему заявлению сценария , как , но это ничего не значит . Спасибо, что указали сценарий, в котором это может быть полезно.
Ливен Кеерсмэкерс
4
@Remus: значит, вы имеете в виду нишевую ситуацию, когда у вас есть неуникальный столбец, например «Departmentid», где вы запрашиваете что-то вроде «DepartmentId BETWEEN 1 и 100»? редактировать ах, я понимаю, что вы имеете в виду, да, столбец даты в таблице регистрации также является хорошим примером.
littlegreen
Привет, у меня есть таблица потока событий, в которой существует несколько строк с одним и тем же «AggregateId», который представляет собой GUID типа fo столбца. Единственные запросы, выполняемые в таблице, - это получение всех событий для данного AggregateId. Мне интересно, должен ли это быть кластерный индекс или некластеризованный индекс?
Shayan C
@ShayanC - Если ваша основная цель - производительность поиска, я бы сделал его CI, чтобы, вероятно, сэкономить на вводе-выводе при получении всех строк для данного идентификатора. Однако, как и во всех сценариях производительности, единственный надежный способ - это измерить.
Ливен Кеерсмэкерс
32

Мне нравится проверять, что королева индексации Кимберли Трипп говорит по этой теме:

Я собираюсь начать с моей рекомендации по ключу кластеризации - по нескольким причинам. Во-первых, это несложное решение, а во-вторых, заблаговременное принятие этого решения помогает заранее предотвратить некоторые типы фрагментации. Если вы можете предотвратить определенные типы фрагментации базовой таблицы, то вы можете свести к минимуму некоторые действия по обслуживанию (некоторые из которых в SQL Server 2000 И меньше в SQL Server 2005) требуют, чтобы ваша таблица была отключена. Хорошо, я займусь восстановлением позже ...

Начнем с ключевых вещей, которые я ищу в ключе кластеризации:

* Unique
* Narrow
* Static

Почему уникальный? Ключ кластеризации должен быть уникальным, поскольку ключ кластеризации (если он существует) используется в качестве ключа поиска для всех некластеризованных индексов. Возьмем, к примеру, указатель в конце книги - если вам нужно найти данные, на которые указывает запись указателя - эта запись (запись указателя) должна быть уникальной, в противном случае, какая запись указателя будет той, которую вы ищете ? Итак, когда вы создаете кластерный индекс - он должен быть уникальным. Но SQL Server не требует, чтобы ваш ключ кластеризации создавался в уникальном столбце. Вы можете создать его в любом столбце (ах) по своему желанию. Внутренне, если ключ кластеризации не является уникальным, SQL Server «унифицирует» его, добавляя к данным 4-байтовое целое число. Таким образом, если кластеризованный индекс создается для чего-то, что не является уникальным, это означает не только дополнительные накладные расходы при создании индекса, но и потраченное впустую дисковое пространство,

Источник: постоянно растущие споры о кластеризации - снова!

marc_s
источник
Вопрос, однако, в том, что королева рекомендует использовать newsequentialid для унификации данных, но SQL Server генерирует свой собственный уникальный идентификатор, если вы его не указываете. Есть ли еще какие-то причины для добавления собственного последовательного идентификатора?
littlegreen
2
@littlegreen: она говорит, что если вы настаиваете на использовании GUID (которые действительно очень плохи для использования в индексе кластеризации), то, по крайней мере, используйте newsequentialid()для получения почти последовательного GUID. Но да: если вы добавляете свой собственный уникальный идентификатор (я всегда предпочитаю INT IDENTITY), тогда у вас есть это значение под рукой, и вы можете его использовать (например, для установления отношения FK). Уникальные свойства, добавленные SQL Server, невидимы для вас и, следовательно, они только накладные расходы, которые вы не можете использовать.
marc_s
Понимаю. Что ж, это был бы аргумент в пользу кластерного индекса (CompanyID, DepartmentID, id INT IDENTITY) вместо первых двух. Благодаря!
littlegreen
1
@littlegreen: еще лучше - сделайте кластерный индекс только на (ID INT IDENTITY) и поместите другие поля - при необходимости - в отдельный некластеризованный индекс. Кластеризованный индекс должен быть как можно меньше - в конце концов, столбцы кластеризованного индекса добавляются к каждой записи каждого некластеризованного индекса в этой таблице - так что не тратьте свои байты на широкий кластеризованный индекс. индекс!
marc_s
1
Да, но тогда я теряю возможность сгруппировать все данные моего отдела, и я могу вставлять / удалять / извлекать сразу весь отдел. Мои данные будут разбросаны, и вставка / удаление по целым отделам или даже целым компаниям будет выполняться медленно. Мои запросы одновременно выполняются только в одной компании, и часто необходимо обновлять весь набор данных.
Littlegreen
9

Должны ли кластерные индексы быть уникальными?

Они этого не делают, и бывают случаи, когда лучше, если это не так.

Рассмотрим таблицу с полуслучайным, уникальным EmployeeId и DepartmentId для каждого сотрудника: если ваш оператор выбора

SELECT * FROM EmployeeTable WHERE DepartmentId=%DepartmentValue%

тогда лучше всего для производительности, если DepartmentIdэто кластерный индекс, хотя (или даже особенно потому, что) это не уникальный индекс (лучше всего для производительности, потому что он обеспечивает кластеризацию всех записей в пределах данного DepartmentId).


Есть ли у вас ссылки?

Там же кластерный индекс Design Guidelines , например, в котором говорится,

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

  • Может использоваться для часто используемых запросов.
  • Обеспечивают высокую степень уникальности.
  • Может использоваться в запросах диапазона.

Я понимаю, например, что «высокая степень уникальности» состоит в том, что нехорошо выбирать «Страна» в качестве кластерного индекса, если большинство ваших запросов хотят выбирать записи в данном городе.

ChrisW
источник
Да, я так думал до сих пор, но я также получил совершенно противоположный совет, поэтому мне интересно, какой из них является правдой. Есть ли у вас ссылки?
littlegreen
@littlegreen Я отредактировал свой ответ, чтобы попытаться ответить на ваш вопрос.
ChrisW 02
Благодарю. Да ладно, я понимаю твою точку зрения. Но если вы регулярно вставляете сразу целую страну, кластерный индекс (страна, город) мне может показаться громоздким, поскольку он требует сортировки данных. С другой стороны, сортировка перед вставкой не составит особого труда ...
littlegreen
3
Конечно, в вашем примере предпочтительнее использовать уникальный кластерный индекс для {DepartmentID, EmployeeID}? Зачем системе нужно создавать уникальный определитель, если ваше существующее поле обеспечит уникальность с меньшими накладными расходами (вероятно, четырехбайтовым INT) и может позволить вам выполнить еще несколько запросов в пределах одного индекса?