Rene Bustos Ответов: 3

Два индекса таблицы могут быть активированы одновременно


Привет, Народ.
Мне интересно, есть ли у меня таблица с двумя индексами. первый тип данных Int, второй тип данных DateTime


если мне нужно сделать запрос, который ищет результаты с помощью ColumnTypeInt и ColumnTypeDateTime
Индексы могут быть активированы? или что произошло в этом случае?


SELECT * FROM Table WHERE ColumnTypInt=12345 AND ColumnTypeDateTime='2018-04-26'


С уважением.

Рене

Что я уже пробовал:

Я выполняю запрос, но результаты занимают много времени.

3 Ответов

Рейтинг:
2

OriginalGriff

Один из способов сделать это может заключаться в использовании вычисляемого столбца и индексировании этого столбца: Как создать индексы в вычисляемых столбцах SQL Server[^]
Кроме того, вы можете иметь несколько индексов в одной таблице.

Это действительно будет зависеть от того, что вы делаете с таблицей, нет никаких решений "один размер подходит всем", которые дадут вам наилучшие результаты.

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


Rene Bustos

спасибо тебе, Оригиналгрифф.
Я прочитаю эти документы, чтобы улучшить свои знания об индексах
С уважением.

OriginalGriff

Всегда пожалуйста!

Рейтинг:
2

Richard Deeming

Проверьте расчетный или фактический план выполнения в SSMS, чтобы узнать, какой индекс используется:
Показать предполагаемый план выполнения | Майкрософт документы[^]
Отображение фактического плана выполнения | Microsoft Docs[^]

Вы можете создать индекс для нескольких столбцов, что может помочь. Однако, поскольку вы выбираете каждый столбец из таблицы, оптимизатор запросов может решить - возможно, неправильно - что более эффективно сканировать всю таблицу, а не искать по индексу, а затем выполнять поиск RID для каждой строки.


Rene Bustos

Спасибо, Ричард.
Я прочитаю эти документы, чтобы улучшить свое знание о плане исполнения.
С уважением.

Рейтинг:
10

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. После поиска используется хэш-соединение для объединения результатов.

Однако имейте в виду, что невозможно сказать, является ли это правильным подходом для вас. Это зависит от нескольких факторов, таких как:
- Какова расчетная мощность для ваших фактических таблиц и столбцов
- Какие еще виды высказываний вы используете
- Являются ли фактические запросы с использованием соединений и в каком порядке
- И так далее...


Rene Bustos

Спасибо, Венделиус.
очень объяснено, и примеры были правильными для моего вопроса.
С уважением.