Зачем использовать INCLUDE в индексе SQL

Недавно я столкнулся с индексом в базе данных, которая, как я утверждаю, имеет форму:

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

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

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

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

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

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

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

Ответ 1

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

В вашем случае у вас есть таблица 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, SubId), все страницы в индексе имеют оба столбца - все дерево индексов.

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

Это означает

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

Ответ 2

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

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

Ответ 3

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