На какой столбец следует кластеризовать индекс? - PullRequest
9 голосов
/ 17 сентября 2009

В последнее время я занимался чтением индексов всех типов, и главный совет - поместить кластерный индекс в первичный ключ таблицы, но что если первичный ключ фактически не используется в запросе select or join) и просто помещается для чисто реляционных целей, поэтому в этом случае он не запрашивается. Например, скажем, у меня есть таблица car_parts, и она содержит 3 столбца: car_part_id, car_part_no и car_part_title. car_part_id - уникальный столбец идентификатора первичного ключа. В этом случае car_part_no также является уникальным и, скорее всего, car_part_title. car_part_no - это то, к чему чаще всего обращаются, поэтому не имеет ли смысла кластеризованный индекс в этот столбец вместо car_part_id? Суть вопроса в том, какой столбец должен иметь кластерный индекс, поскольку вам разрешен только один из них?

Ответы [ 5 ]

8 голосов
/ 17 сентября 2009

Индекс, кластеризованный или не заблокированный, может использоваться оптимизатором запросов тогда и только тогда, когда фильтруется самый левый ключ в индексе. Поэтому, если вы определяете индекс для столбцов (A, B, C), условие WHERE для B=@b, C=@c или B=@b AND C=@c не будет полностью использовать индекс (см. Примечание). Это относится и к условиям присоединения. Любой фильтр WHERE, включающий A, будет учитывать индекс: A=@a или A=@a AND B=@b или A=@a AND C=@c или A=@a AND B=@b AND C=@c.

Так что в вашем примере, если вы сделаете индекс clustred для part_no в качестве крайнего левого ключа, тогда запрос, ищущий конкретный part_id, будет не использовать индекс и отдельный некластеризованный индекс должен существовать в part-id.

Теперь о том, какой из множества индексов должен быть кластеризованным . Если у вас есть несколько шаблонов запросов, которые имеют примерно одинаковую важность и частоту и противоречат друг другу с точки зрения необходимых ключей (например, частые запросы по или part_no или part_id), тогда вы принимаете другие факторы во внимание:

  • ширина : ключ кластеризованного индекса используется в качестве ключа поиска для всех других некластеризованных индексов. Поэтому, если вы выберете широкий ключ (скажем, два столбца-идентификатора), вы сделаете все остальные индексы более широкими, занимая тем самым больше места, создавая больше операций ввода-вывода и замедляя все. Таким образом, между одинаково хорошими ключами с точки зрения чтения выберите самый узкий как кластеризованный и сделайте более широкие некластеризованными.
  • contention : если у вас есть определенные шаблоны вставки и удаления, попробуйте разделить их физически, чтобы они встречались в разных частях кластеризованного индекса. Например. если таблица действует как очередь со всеми вставками на одном логическом конце и удаляет все на другом логическом конце, попытайтесь расположить кластеризованный индекс так, чтобы физический порядок соответствовал этому логическому порядку (например, порядок очереди).
  • разбиение : если таблица очень большая и вы планируете развернуть разделение, то ключ разделения должен быть кластеризованным индексом. Типичным примером являются исторические данные, которые архивируются с использованием схемы секционирования скользящего окна. Даже если у сущностей есть логический первичный ключ, такой как «entity_id», индекс с привязкой делается столбцом datetime, который также используется для функции разделения.
  • стабильность : часто меняющийся ключ является плохим кандидатом для кластеризованного ключа, так как каждый обновляет значение кластеризованного ключа и вынуждает все некластеризованные индексы обновлять ключ поиска, который они хранить. Обновление кластеризованного ключа также может переместить запись на другую страницу, что может привести к фрагментации кластерного индекса.

Примечание: не использовать полностью , так как иногда механизм будет выбирать некластеризованный индекс для сканирования вместо кластеризованного индекса просто потому, что он уже и поэтому для сканирования меньше страниц. В моем примере, если у вас есть индекс на (A, B, C) и фильтр WHERE на B=@b, а запрос проецирует C, индекс, скорее всего, будет использоваться, но не как поиск, а как сканирование, потому что все еще быстрее, чем полное кластерное сканирование (меньше страниц).

4 голосов
/ 17 сентября 2009

Кимберли Трипп всегда является одним из лучших источников информации об индексации.

См. Ее сообщение в блоге " Постоянно увеличивающийся ключ кластеризации - дебаты по кластерному индексу - снова! ", в котором она довольно четко перечисляет и объясняет основные требования для хорошего ключа кластеризации - это должно быть:

  • Уникальная
  • Узкое
  • Статический

и лучше всего, если вы можете управлять:

  • постоянно увеличивающийся

Принимая все это во внимание, INT IDENTITY (или BIGINT IDENTITY, если вам действительно нужно более 2 миллиардов строк) - лучший выбор в подавляющем большинстве случаев.

Одна вещь, которую многие люди не понимают (и, следовательно, не учитывают при выборе), это то, что ключ кластеризации (все столбцы, составляющие кластеризованный индекс) будет добавлен к каждому и каждая запись индекса для каждого некластеризованного индекса в вашей таблице - таким образом, «узкое» требование становится очень важным!

Кроме того, поскольку ключ кластеризации используется для поиска закладок (поиск фактической строки данных, когда строка найдена в некластеризованном индексе), требование «уникальности» также становится очень важным. На самом деле настолько важно, что если вы выберете (набор) столбцов, которые / не будут гарантированно уникальными, SQL Server добавит 4-байтовый uniquefier в каждую строку -> тем самым сделав каждый из ваших ключи кластерного индекса очень широкие; определенно НЕ хорошая вещь.

Марк

4 голосов
/ 17 сентября 2009

Кластерные индексы хороши, когда вы запрашиваете диапазоны данных. Например

SELECT * FROM theTable WHERE age BETWEEN 10 AND 20

Кластерный индекс размещает строки в определенном порядке на диске вашего компьютера. Поэтому ряды с возрастом = 10 будут рядом друг с другом, а после них будут строки с возрастом = 11 и т. Д.

Если у вас есть точный выбор, например:

SELECT * FROM theTable WHERE age = 20

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

Так что это сильно зависит от типа выполняемых вами запросов.

2 голосов
/ 17 сентября 2009

Имейте в виду схемы использования; Если вы почти всегда запрашиваете БД для car_part_no, то, вероятно, было бы полезно кластеризовать ее в этом столбце.

Однако не забывайте о соединениях; Если вы чаще всего присоединяетесь к таблице, а объединение использует поле car_part_id, у вас есть веская причина оставить кластер на car_part_id.

Следует иметь в виду еще кое-что (в данном случае меньше, но обычно при рассмотрении кластеризованных индексов), что кластеризованный индекс будет отображаться неявно в любом другом индексе таблицы; Так, например, если вы хотите индексировать car_part_title, этот индекс будет также неявно включать car_part_id. Это может повлиять на то, покрывает ли индекс запрос или нет, а также на то, сколько дискового пространства он займет (что влияет на использование памяти и т. Д.).

1 голос
/ 17 сентября 2009

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

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

Некоторые дополнительные рекомендации по выбору кластеризованной таблицы можно найти в MSDN здесь: Рекомендации по проектированию кластерного индекса .

...