Ищет ли MS SQL в нескольких индексах или выбирает только один наиболее оптимальный?
Допустим, есть таблица с колонками A и B. На каждой колонке есть собственный индекс.
Так вот, если условие отбора будет по A и B, то SQL Server воспользуется самым оптимальным индексом, а вторым не будет пользоваться или все таки воспользуется обоими, например, отобрав сначала по одному индексу, а затем воспользовавшись на результатах отбора вторым индексом?
Я склоняюсь, что будет выбран только оддин индекс, но что-то нагуглить подтверждения не могу...
Ответы (1 шт):
Допустим, есть таблица с колонками A и B. На каждой колонке есть собственный индекс.
... если условие отбора будет по A и B, то SQL Server воспользуется самым оптимальным индексом, а вторым не будет пользоваться или все таки воспользуется обоими ... ?
Оптимизатор может использовать оба индекса, может только один какой-то, может ни одним из индексов не воспользоваться. В общем случае это зависит от запроса, определения таблицы и индексов, данных в таблице, состояния статистик, версии SqlServer, настроек сессии и других факторов.
Вот пример, когда оптимизатор использует два индекса на одной таблице.
Таблица
CREATE TABLE #dummy
(
Id int PRIMARY KEY,
A char(1),
B char(1),
Filler binary(100)
);
Данные
INSERT INTO #dummy (Id, A, B, Filler)
SELECT N, CHAR(48 + N % 10), CHAR(65 + N % 26), 0x
FROM Numbers -- таблица с натуральными числами
WHERE N BETWEEN 1 AND 10000;
Индексы
CREATE INDEX IX_dummy_A ON #dummy (A);
CREATE INDEX IX_dummy_B ON #dummy (B);
Запрос с условием AND по столбцам A и B
SELECT Id
FROM #dummy
WHERE A = '7' AND B = 'F';
План запроса
т.е. фактически оптимизатор преобразовал запрос в соединение
SELECT ixb.Id
FROM (
SELECT Id
FROM #dummy WITH (INDEX(IX_dummy_B))
WHERE B = 'F'
) ixb
JOIN (
SELECT Id
FROM #dummy WITH (INDEX(IX_dummy_A))
WHERE A = '7'
) ixa ON ixa.Id = ixb.Id;
Теперь с условием OR по столбцам A и B
SELECT Id
FROM #dummy
WHERE A = '7' OR B = 'F';
что эквивалентно выборке без повторов из объединения
SELECT DISTINCT Id
FROM (
SELECT Id
FROM #dummy WITH (INDEX(IX_dummy_A))
WHERE A = '7'
UNION ALL
SELECT Id
FROM #dummy WITH (INDEX(IX_dummy_B))
WHERE B = 'F'
) u;
Запрос с условием AND по столбцам A и B, но индексы не покрывают запрос
SELECT *
FROM #dummy
WHERE A = '7' AND B = 'F';
отчасти похоже на первый случай, но добавилось соединение с Key Lookup, чтобы достать данные столбца Filler.
Этот же запрос, но с OR
SELECT *
FROM #dummy
WHERE A = '7' OR B = 'F';
и оптимизатор решает, что сканирование кластерного индекса выгоднее
Та же самая таблица, те же индексы, но другие данные, первый запрос (SELECT Id ... WHERE ... AND ...)
оптимизатор использует только один индекс (по столбцу B), добирая остальное из кластерного индекса.




