Работают ли индексы с предложением IN - PullRequest
27 голосов
/ 28 августа 2008

Если у меня есть запрос типа:

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

и у меня есть индекс в поле EmployeeTypeId, SQL-сервер все еще использует этот индекс?

Ответы [ 6 ]

17 голосов
/ 28 августа 2008

Да, все верно. Если ваша таблица сотрудников имеет 10 000 записей, и только 5 записей имеют идентификатор сотрудника в (1,2,3), то, скорее всего, он будет использовать индекс для извлечения записей. Однако, если он обнаружит, что 9000 записей имеют employeeIDType в (1,2,3), то он, скорее всего, просто выполнит сканирование таблицы, чтобы получить соответствующие EmployeeIDs, так как быстрее всего пройти через всю таблицу, чем перейти каждую ветвь дерева индексов и смотрите на записи по отдельности.

SQL Server делает много вещей, чтобы попытаться оптимизировать работу запросов. Однако иногда это не дает правильного ответа. Если вы знаете, что SQL Server не использует индекс, просмотрев план выполнения в анализаторе запросов, вы можете указать обработчику запросов использовать определенный индекс со следующим изменением вашего запроса.

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

Предполагается, что индекс, который у вас есть в поле EmployeeTypeId, называется Index_EmployeeTypeId.

4 голосов
/ 28 августа 2008

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

3 голосов
/ 28 августа 2008

Если технология не улучшилась так, как я не могу представить в последнее время, показанный запрос "IN" даст результат, который фактически будет OR из трех наборов результатов, по одному для каждого из значений в списке "IN" , Предложение IN становится условием равенства для каждого списка и при необходимости будет использовать индекс. В случае уникальных идентификаторов и достаточно большой таблицы, я ожидаю, что оптимизатор будет использовать индекс.

Однако, если элементы в списке должны быть неуникальными, и я предполагаю, что в примере «TypeId» является внешним ключом, тогда меня больше интересует распределение. Мне интересно, будет ли оптимизатор проверять статистику для каждого значения в списке? Скажем, он проверяет первое значение и находит его в 20% строк (достаточно большой таблицы, чтобы иметь значение). Это, вероятно, будет сканирование таблицы. Но будет ли использоваться тот же план запроса для двух других, даже если они уникальны?

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

И, наконец, пока я проповедую, остерегайтесь запроса в предложении IN: часто это быстрый способ заставить что-то работать и (по крайней мере для меня) может быть хорошим способом выразить требование, но это почти всегда лучше переформулировать как объединение. Ваш оптимизатор может быть достаточно умен, чтобы заметить это, но с другой стороны это может и не быть. Если вы в настоящее время не проверяете производительность по объемам производственных данных, сделайте это - в наши дни оптимизации на основе затрат вы не можете быть уверены в плане запроса, пока не получите полную загрузку и репрезентативную статистику. Если вы не можете, тогда будьте готовы к неожиданностям в производстве ...

2 голосов
/ 28 августа 2008

Таким образом, есть возможность для предложения IN выполнить сканирование таблицы, но оптимизатор попытаться найти лучший способ справиться с этим?

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

Другие плакаты верны, что индекс будет использоваться для сканирования таблицы, если:

  • Запрос не будет обращаться к более чем определенному проценту проиндексированных строк (скажем, ~ 10%, но должен варьироваться в зависимости от СУБД).
  • В качестве альтернативы, если в столбце много строк, но относительно мало уникальных значений, сканирование таблицы также может быть быстрее.

Другая переменная, которая может быть не столь очевидной, - это проверка того, что типы данных сравниваемых значений совпадают. В PostgreSQL я не думаю, что индексы будут использоваться, если вы фильтруете по float, но ваш столбец состоит из целых чисел. Есть также некоторые операторы, которые не поддерживают использование индекса (опять же, в PostgreSQL оператор ILIKE такой же).

Как уже отмечалось, всегда проверяйте анализатор запросов, если сомневаетесь, и документация вашей СУБД принадлежит вам.

1 голос
/ 29 августа 2008

@ Майк: Спасибо за подробный анализ. Там определенно есть некоторые интересные моменты, которые вы делаете. Приведенный мною пример несколько тривиален, но в основе вопроса лежит использование NHibernate.

С помощью NHibernate вы можете написать следующее предложение:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

Затем NHibernate генерирует запрос, который выглядит как

select * from employee where employeeid in (1, 5, 23463, 32523)

Итак, как вы и другие указали, похоже, что будут времена, когда будет использоваться индекс, или будет выполняться сканирование таблицы, но вы не сможете определить это до времени выполнения.

0 голосов
/ 24 мая 2017
Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

Этот запрос будет искать с использованием индекса, который вы создали. Меня устраивает. Пожалуйста, попробуйте ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...