Охватывающие индексы, когда дополнительные столбцы однозначно определяются кластеризованным индексом
-
20-09-2019 - |
Вопрос
Предположим, мне нужно обновить MyTab из luTab следующим образом
update myTab
set LookupVale = (select LookupValue from luTab B
where B.idLookup = myTab.idLookup)
luTab состоит из 2 столбцов (idLookup (уникальный), LookupValue)
Что предпочтительнее :уникальный кластеризованный индекс в idLookup или один в idLookup и Lookupvalue вместе взятых?Будет ли индекс покрытия иметь какое-либо значение в этой ситуации?
(Меня больше всего интересует SQL server)
Эпилог :
Я проследил за приведенными ниже тестами Крипса с 27 миллионами строк в MyTab, 1,5 миллионами строк в luTab.Решающей частью, по-видимому, является уникальность индекса.Если индекс указан как уникальный, при обновлении используется хэш-таблица.Если он не указан как уникальный, то обновление сначала увеличивает luTab с помощью idLookup (Stream Aggegate), а затем использует вложенный цикл.Это происходит намного медленнее.Когда я использую расширенный индекс, SQL теперь больше не уверен, что это поисковое значение уникально, поэтому он использует гораздо более медленный маршрут с потоковым агрегированным вложенным циклом
Решение
Я создал ваши таблицы и загрузил всего несколько записей (около 50 для поиска и 15 в MyTab).
Затем я попробовал различные варианты индексации.Стоимость поиска индекса на luTab всегда составляет 29%.
Интересным моментом является то, что если вы добавите столбец LookupValue к индексу в luTab, план выполнения покажет два дополнительных шага после поиска по индексу:Поток агрегирует и утверждает.Хотя стоимость составляет 0%, она может увеличиться с увеличением объема данных.
Я также пробовал некластеризованный индекс только для idLookup и включал LookupValue в качестве "Включенного столбца".Таким образом, для извлечения этого столбца не нужно обращаться к страницам данных.Это может быть вариантом для вас, хотя план выполнения не показывает ничего другого (но у них также нет Stream Aggregate / Assert).
-Крип
Другие советы
Во- первых:
- Покрывающий индекс всегда является некластеризованным
- У вас всегда должны быть PK и кластеризованный индекс (по умолчанию на SQL Server они одинаковы).
Эти 2 понятия разделены
Итак:
- Ваш PK (кластеризованный) будет idLookup, если это однозначно идентифицирует строку
- Охватывающий индекс будет (idLookup) ВКЛЮЧАТЬ (LookupValue)
Однако:
- idLookup - это PK (кластеризованный), поэтому вам не нужен покрывающий индекс
- кластеризованный индекс (PK) неявно "покрывает" по природе кластеризованного индекса (проще говоря, индекс - это данные на самом низком уровне).