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

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

CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)

-- или --

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

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

7 ответов


если столбец не находится в WHERE/JOIN/GROUP BY/ORDER BY, но только в списке столбцов в SELECT предложения.

на INCLUDE предложение добавляет данные на самом низком уровне / leaf, а не в дереве индекса. Это делает индекс меньше, потому что он не является частью дерева

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

еще одна статья MSDN с работающим примером


вы могли бы использовать INCLUDE для добавления одного или нескольких столбцов на уровень листа некластеризованного индекса, если таким образом вы можете "покрыть" свои запросы.

представьте, что вам нужно запросить идентификатор сотрудника, идентификатор отдела и фамилию.

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Если у вас есть некластеризованный индекс (EmployeeID, DepartmentID), как только вы найдете сотрудников для данного отдела, теперь вам нужно сделать "поиск закладок", чтобы получить фактическую полную запись сотрудника, просто чтобы получить столбец lastname. Это может быть довольно дорого с точки зрения производительности, если вы найдете большое количество сотрудников.

Если бы вы включили это последнее имя в свой индекс:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

тогда вся необходимая информация доступна на уровне листа некластеризованного индекса. Просто при поиске в некластеризованном индексе и поиске сотрудников для данного отдела у вас есть вся необходимая информация, а поиск закладок для каждого сотрудника, найденного в индексе, больше не выполняется необходимо --> вы экономите много времени.

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


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


в этом обсуждении отсутствует важный момент: вопрос не в том, что "неключевые столбцы" лучше включать как индекс-столбцы или как входит-столбцы.

вопрос в том, насколько дорого использовать механизм включения для включения столбцов, которые не очень нужен в index? (обычно не входит в WHERE-предложения, но часто включается в selects). Так что ваша дилемма всегда:

  1. использовать индекс на типа id1, ID2, которое ... idN только или
  2. использовать на типа id1, ID2, которое ... idN плюс столбец col1, и col2 ... кольн!--14-->

где: типа id1, ID2, которое ... idN-это столбцы, часто используемые в ограничениях и col1, col2 ... colN-это столбцы, которые часто выбираются, но обычно не используемых в ограничениях

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

поэтому используйте вариант 1 или 2?

ответ: Если ваша таблица редко обновляется-в основном вставляется/удаляется из - тогда относительно недорого использовать механизм включения для включения некоторых "горячих столбцов" (которые часто используются в selects - but не часто используется для ограничений), так как вставки / удаления требуют, чтобы индекс был обновлено / Отсортировано в любом случае, и поэтому небольшие дополнительные накладные расходы связаны с сохранением нескольких дополнительных столбцов при обновлении индекса. Накладные расходы-это дополнительная память и процессор, используемые для хранения избыточной информации в индексе.

Если столбцы, которые вы считаете добавить как включенные-столбцы часто обновляются (без индекса -ключ-столбцы обновляются) - или - если их так много, что индекс становится близким к копии вашей таблицы - используйте вариант 1 я бы предложите! Кроме того, если добавление определенных include-column(s) оказывается не имеет значения производительности-вы можете пропустить идею их добавления:) убедитесь, что они полезны!

среднее количество строк на одинаковые значения в ключах (id1, id2 ... idN) также может иметь некоторое значение.

обратите внимание, что если столбец-то добавляется как входит-столбец индекса - используется в ограничение: пока индекс как таковой может быть используется (на основе ограничения по индексу -ключ - columns)-тогда SQL Server сопоставляет ограничение столбца с индексом (значения листового узла) вместо того, чтобы идти дорогой путь вокруг самой таблицы.


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


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

Это позволяет включать такие столбцы в индекс покрытия. Недавно мне пришлось сделать это, чтобы предоставить запрос nHibernate, в котором было много столбцов в SELECT, с полезным индексом.


существует ограничение на общий размер всех столбцов, встроенных в определение индекса. Тем не менее, мне никогда не приходилось создавать индекс такой ширины. Для меня большим преимуществом является тот факт, что вы можете охватить больше запросов одним индексом, который включает столбцы, поскольку они не должны определяться в каком-либо определенном порядке. Думаю о том, как индекс в индексе. Одним из примеров может быть StoreID (где StoreID-низкая избирательность, означающая, что каждый магазин связан с большим количеством клиенты), а затем демографические данные клиентов (Фамилия, Имя, DOB): Если вы просто встроите эти столбцы в этом порядке (StoreID, LastName, FirstName, DOB), вы можете эффективно искать клиентов, для которых вы знаете StoreID и LastName.

с другой стороны, определение индекса на StoreID и включая LastName, FirstName, DOB столбцы позволят вам, по сути, сделать два предиката seeks - index на StoreID, а затем искать предикат на любом из включенных столбцов. Это позволит вы охватывать все возможные permutationsas поиск если он начинается с поле storeid.