Wendelius
Во-первых, вы не активируете индексы. Оптимизатор SQL Server принимает решение о том, будет ли использоваться индекс (или несколько индексов) или нет. Ваша задача состоит в том, чтобы убедиться, что у вас есть правильные индексы, но также и в том, что вы не переиндексируете, так как это ухудшит производительность для модификаций.
Сказав это, вернемся к вашему актуальному вопросу: Да, один запрос в одной таблице может использовать несколько индексов, если оптимизатор считает это разумным. Это делается путем "соединения индексов". Другими словами, получение rowid отдельно от двух индексов, а затем создание внутреннего соединения с результатами.
Это можно проверить с помощью простого теста. Сначала давайте создадим таблицу
CREATE TABLE IndexTest (
col1 int,
col2 date
);
GO
А затем добавьте в него разумное количество данных. Данные должны содержать повторяющиеся значения, чтобы один индекс не был слишком избирательным
SET NOCOUNT ON;
DECLARE
@counter1 int,
@counter2 int,
@col1 int;
BEGIN
SET @counter1 = 0;
WHILE @counter1 <= 1000 BEGIN
SET @col1 = @counter1;
SET @counter2 = 1;
WHILE @counter2 <= 1000 BEGIN
INSERT INTO IndexTest (col1, col2) VALUES (@col1, GETDATE() + ROUND(RAND()*100,0))
SET @counter2 = @counter2 + 1;
END;
SET @counter1 = @counter1 + 1;
END;
END;
GO
Теперь у нас есть немного больше 1'000'000 строк.
Давайте создадим наши индексы
CREATE INDEX X1 ON IndexTest (col1);
CREATE INDEX X2 ON IndexTest (col2);
Теперь рассмотрим следующий запрос
SELECT *
FROM IndexTest
WHERE col1 = 123
AND col2 = CAST((GETDATE() + 2) AS DATE)
Оба условия будут возвращать тысячу или более строк по отдельности, но фактический результат, скорее всего, будет намного меньше. В моем тестовом запуске запрос вернул 13 строк.
Итак, давайте посмотрим, как был выполнен запрос. План выполнения выглядит следующим образом
|--Hash Match(Inner Join, HASH:([Bmk1000])=([Bmk1000]), RESIDUAL:([Bmk1000] = [Bmk1000]))
|--Index Seek(OBJECT:([IndexTest].[X1]), SEEK:([IndexTest].[col1]=(123)) ORDERED FORWARD)
|--Index Seek(OBJECT:([IndexTest].[X2]), SEEK:([IndexTest].[col2]=CONVERT(date,getdate()+CONVERT_IMPLICIT(datetime,[@2],0),0)) ORDERED FORWARD)
Таким образом, как вы можете видеть, используются два отдельных индексных поиска, один на X1, а другой на X2. После поиска используется хэш-соединение для объединения результатов.
Однако имейте в виду, что невозможно сказать, является ли это правильным подходом для вас. Это зависит от нескольких факторов, таких как:
- Какова расчетная мощность для ваших фактических таблиц и столбцов
- Какие еще виды высказываний вы используете
- Являются ли фактические запросы с использованием соединений и в каком порядке
- И так далее...