У меня есть таблицы Log и LogItem; Я пишу запрос, чтобы получить некоторые данные из обоих. Есть тысячи, Logs
и каждый Log
может иметь до 125LogItems
Данный запрос сложен, поэтому я его пропускаю (если кто-то считает, что это важно, я, вероятно, могу опубликовать его), но когда я запустил план оценочных запросов SSMS, он сказал мне, что новый некластеризованный индекс повысит производительность до 100%. ,
Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified
Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])
Просто для забавы я создал этот новый индекс и выполнил запрос, и, к моему большому удивлению, теперь мой запрос выполняется ~ 1 секунда, тогда как раньше это было более 10 секунд.
Я предполагал, что мой существующий индекс будет охватывать этот новый запрос, поэтому мой вопрос заключается в том, почему создание нового индекса только для столбцов, используемых в моем новом запросе, повысило производительность? Должен ли я иметь индекс для каждой уникальной комбинации столбцов, используемых в моих where
предложениях?
примечание: я не думаю, что это происходит из-за того, что SQL Server кэширует мои результаты, я выполнил запрос примерно 25-30 раз, прежде чем создал индекс, и он последовательно занимал 10-15 секунд, после индекса он теперь постоянно ~ 1 или менее.
источник
Ответы:
Порядок столбцов в индексе важен. Если для фильтрации требуются столбцы 1 и 4 из индекса, индекс не поможет. Это полезно только при фильтрации по первым N последовательным столбцам.
Это потому, что индекс это дерево. Вы не можете эффективно выбрать все узлы дерева где
column3 = something
, потому что они разбросаны по всем остальным местам, принадлежащим разным значениямcolumn1
иcolumn2
. Но если вы знаете ,column1
иcolumn2
как хорошо, местонахождение правой ветви в дереве является не просто.источник
where
s могут перекрываться, поэтому у вас может быть индекс, который хорошо покрывает несколькоwhere
s; или вы можете игнорировать некоторую частьwhere
предложения, потому что индексирование по определенному столбцу в любом случае не поможет (низкая селективность); но в целом да.where
предложениях не важен. Сервер всегда организует их так, чтобы наилучшим образом использовать существующие индексы. Вопрос только в том, чтобы индекс включал все обязательныеwhere
столбцы в качестве первых столбцов.Передний край индекса является то , что имеет значение.
Пока ваш запрос «покрыт» передним краем индекса, он будет эффективным. Индексы базы данных обычно реализуются в виде B-деревьев, а структура B-дерева диктует, что поиск должен выполняться в определенном порядке, поэтому порядок полей в составном индексе имеет значение.
Если у вас есть «дыры», например, если вы выполняете поиск
ParentLogID
иDatabaseModified
, но имеете только индекс{ParentLogID, DateModified, Name, DatabaseModified}
, то только{ParentLogID}
часть индекса может быть эффективно использована.(ПРИМЕЧАНИЕ. Некоторые СУБД могут использовать эту
{DatabaseModified}
часть через «сканирование с пропуском», но даже если ваша СУБД делает это, она гораздо менее эффективна, чем обычный индексный доступ) .источник
Columns (a, b, c, d, e, f)
и большинство запросов -... WHERE A IN(...) AND B = 3
мой индекс,Index(a,b,c,d)
который является хорошим, но это не поможет, если у меня есть,... WHERE A IN (...) AND D = 5
именно поэтому мой новый индекс, который я сделал,Index(a,d)
так сильно улучшил производительность, верно?