Зачем использовать INCLUDE в индексе SQL - PullRequest
14 голосов
/ 13 марта 2010

Я недавно столкнулся с индексом в поддерживаемой мной базе данных, которая имела вид:

CREATE INDEX [IX_Foo] ON [Foo]
( Id ASC )
INCLUDE 
( SubId )

В этом конкретном случае проблему с производительностью, с которой я столкнулся (медленная фильтрация SELECT как по Id, так и по SubId), можно исправить, просто переместив столбец SubId в собственно индекс, а не как включенный столбец.

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

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

Единственное, о чем я могу подумать, это то, что при наличии обновлений в SubId строку не нужно будет перемещать, если включен столбец (хотя значение в индексе нужно будет изменить). Есть что-то еще, что я пропускаю?

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

Меня в первую очередь интересует MS SQL Server, но приветствуется также информация о других механизмах БД.

Ответы [ 3 ]

8 голосов
/ 13 марта 2010

Пока все ответы верны и все - но они могут не передавать достаточно того, что вы получаете от индекса покрытия.

В вашем случае у вас есть таблица Foo и некоторые поля, включая Id (который я предполагаю, что это первичный ключ), и SubId, который является некоторым дополнительным идентификатором какого-то рода.

У вас также есть индекс IX_Foo, который, я полагаю, на данный момент содержит только Id.

Так что теперь вам нужно найти SubId для Id=4.

SELECT Id, SubId
FROM Foo
WHERE Id=4
  • SQL Server посмотрит на оператор SELECT и определит, что он может использовать IX_Foo
  • Затем он будет искать значение Id=4 в вашем индексе IX_Foo
  • когда он его находит, ему теперь нужно значение SubId, тоже
  • некластеризованный индекс IX_Foo будет содержать значение ключа кластеризации
  • используя это значение ключа кластеризации, SQL Server выполнит «поиск закладок», чтобы найти фактическую страницу данных, на которой находится вся строка данных
  • будет извлекать эту страницу и извлекать из нее значение для SubId
  • вернет эти значения для удовлетворения вашего запроса

Суть в следующем: как только SQL Server обнаружит ваш Id=4 в индексе IX_Foo, ему потребуется выполнить еще одну операцию ввода-вывода, поиск закладок, чтобы получить всю строку данных, в чтобы можно было найти значение SubId.

Если у вас есть индекс покрытия, например, IX_Foo также включает SubId, что лишний ввод / вывод для поиска закладок исключен. Как только значение Id=4 найдено в индексе IX_Foo, эта страница индекса в вашем некластеризованном индексе также будет содержать значение SubId - теперь SQL Server может возвращать те два значения, которые вы запрашивали в своем запросе SELECT без необходимости выполнять дополнительный (потенциально дорогой и, следовательно, медленный) поиск закладок, чтобы просто получить другой столбец Id.

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

ОБНОВЛЕНИЕ: Компромисс заключается в следующем: если у вас есть индекс на (Id, SubId), все страницы в индексе имеют оба столбца - все дерево индекса до конца.

Если вы ВКЛЮЧАЕТЕ (SubId), поля SubId присутствуют только на уровне листа.

Это значит

  • SQL Server не может искать и сравнивать по SubId (значения не находятся в дереве индекса)
  • используется меньше места, так как значения находятся только на уровне листа
7 голосов
/ 13 марта 2010

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

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

3 голосов
/ 13 марта 2010

Использование include в индексе позволяет использовать индекс в качестве покрывающего индекса (т. Е. Некоторые запросы могут быть выполнены с использованием только этого индекса, без необходимости поиска закладок в кластеризованном индексе), без добавления этих столбцов к фактическому древовидная часть индекса, таким образом сохраняя размер индекса вниз. (Включенные столбцы добавляются только в конечные узлы индекса).

...