Ищет ли MS SQL в нескольких индексах или выбирает только один наиболее оптимальный?

Допустим, есть таблица с колонками A и B. На каждой колонке есть собственный индекс.

Так вот, если условие отбора будет по A и B, то SQL Server воспользуется самым оптимальным индексом, а вторым не будет пользоваться или все таки воспользуется обоими, например, отобрав сначала по одному индексу, а затем воспользовавшись на результатах отбора вторым индексом?

Я склоняюсь, что будет выбран только оддин индекс, но что-то нагуглить подтверждения не могу...


Ответы (1 шт):

Автор решения: i-one

Допустим, есть таблица с колонками 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';

План запроса

план 1

т.е. фактически оптимизатор преобразовал запрос в соединение

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';

план 2

что эквивалентно выборке без повторов из объединения

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';

план 3

отчасти похоже на первый случай, но добавилось соединение с Key Lookup, чтобы достать данные столбца Filler.

Этот же запрос, но с OR

SELECT *
FROM #dummy
WHERE A = '7' OR B = 'F';

и оптимизатор решает, что сканирование кластерного индекса выгоднее

план 4

Та же самая таблица, те же индексы, но другие данные, первый запрос (SELECT Id ... WHERE ... AND ...)

план 5

оптимизатор использует только один индекс (по столбцу B), добирая остальное из кластерного индекса.

→ Ссылка