Зачем использовать INCLUDE в индексе SQL
Я недавно столкнулся с индексом в базе данных, которую я поддерживаю, которая имела форму:
CREATE INDEX [IX_Foo] ON [Foo]
( Id ASC )
INCLUDE
( SubId )
В этом конкретном случае проблему с производительностью, с которой я столкнулся (медленная фильтрация SELECT как по Id, так и по SubId), можно исправить, просто переместив столбец SubId в собственно индекс, а не как включенный столбец.
Однако это заставило меня задуматься о том, что я вообще не понимаю причины, стоящие за включенными столбцами, тогда как в общем случае они могут быть просто частью самого индекса. Даже если я не особо беспокоюсь о том, что элементы находятся в самом индексе, есть ли смысл иметь столбец в индексе, а не просто включать его.
После некоторых исследований мне стало известно, что существует ряд ограничений на то, что может входить в индексированный столбец (максимальная ширина индекса и некоторые типы столбцов, которые нельзя индексировать, например, "изображение"). В этих случаях я вижу, что вы будете вынуждены включить столбец в данные страницы индекса.
Единственное, о чем я могу подумать, это то, что при наличии обновлений в SubId строку не нужно будет перемещать, если столбец включен (хотя значение в индексе нужно будет изменить). Есть что-то еще, что я пропускаю?
Я рассматриваю возможность просмотра других индексов в базе данных и смещения включенных столбцов в собственно индексе, где это возможно. Будет ли это ошибкой?
Меня в первую очередь интересует MS SQL Server, но приветствуется и информация о других движках БД.
3 ответа
Пока все ответы верны и все - но они могут не передавать достаточно того, что вы получаете от индекса покрытия.
В вашем случае у вас есть стол 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
index, эта страница индекса в вашем некластеризованном индексе также будет включать значение SubId
- SQL Server теперь может возвращать те два значения, которые вы запрашивали в своем запросе SELECT, без необходимости выполнять дополнительный (потенциально дорогой и, следовательно, медленный) поиск закладок, чтобы просто получить другой столбец Id.
Это основное преимущество охвата индексов - если вам нужен только один или два дополнительных столбца, помимо значений индекса, по которым вы выполняете поиск, включив эти значения в сам индекс, вы можете сэкономить много просмотров закладок и, таким образом, значительно ускорить процесс. Тем не менее, вы должны включать только очень небольшое количество информации - не дублируйте все строки данных во все некластеризованные индексы! Не в этом дело.
ОБНОВЛЕНИЕ: компромисс заключается в следующем: если у вас есть индекс на (Id, SubId), все страницы в индексе имеют оба столбца - все дерево индекса до конца.
Если вы включаете (SubId), поля SubId присутствуют только на уровне листа.
Это означает
- SQL Server не может искать и сравнивать по SubId (значения не находятся в дереве индекса)
- используется меньше места, так как значения находятся только на уровне листа
Причина наличия дополнительного столбца в индексе заключается в том, что при выполнении запроса, который требует только столбцы, используемые индексом, вы можете выполнить запрос из индекса самостоятельно. Таким образом, вы экономите время и ресурсы, возвращаясь к столу. Когда это происходит, мы говорим, что индекс является индексом покрытия для запроса.
Причина, по которой вы, возможно, не захотите делать этот дополнительный столбец частью "правильного индекса", заключается в том, что при вставке или обновлении этого столбца вам, скорее всего, потребуется пересортировать части индекса.
Использование include в индексе позволяет использовать индекс в качестве покрывающего индекса (т. Е. Некоторые запросы могут быть выполнены с использованием только этого индекса, без необходимости выполнять поиск закладок в кластеризованном индексе), без добавления этих столбцов к фактической части дерева индекс, таким образом, сохраняя размер индекса вниз. (Включенные столбцы добавляются только в конечные узлы индекса).