Нужны ли отдельные индексы для каждого типа запроса, или будет работать один многостолбцовый индекс?

22

Я уже немного знаю ответ на этот вопрос, но я всегда чувствую, что мне нужно еще кое-что узнать по этой теме.

Мое базовое понимание состоит в том, что, вообще говоря, единый индекс, который включает в себя все поля, которые вы можете запрашивать / сортировать в любой момент времени, вряд ли будет полезен, но я видел подобные вещи. Например, кто-то подумал: «Ну, если мы просто поместим все эти вещи в индекс, база данных сможет использовать его, чтобы найти то, что ему нужно», даже не видя плана выполнения для некоторых из выполняемых запросов.

Представьте себе таблицу примерно так:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Я мог бы увидеть один индекс в том числе name, customerIdи dateCreatedпол.

Но я понимаю, что такой индекс не будет использоваться в запросе, например:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Для такого запроса, то мне кажется , что лучшая идея будет индексом в том числе customerIdи dateCreatedполе, с customerIdполем является «первым». Это создало бы индекс, в котором данные были бы организованы таким образом, чтобы этот запрос мог быстро найти то, что ему нужно - в том порядке, в котором он нуждается.

Еще одна вещь, которую я вижу, возможно, так же часто, как первая, - это индивидуальные индексы в каждом поле; так, по одному наname , customerIdи dateCreatedполя.

В отличие от первого примера, этот тип расположения иногда кажется мне хотя бы частично полезным; план выполнения запроса может показать, что по крайней мере он использует индекс наcustomerId для выбора записей, но не использует индекс с dateCreatedполем для их сортировки.


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

Но я предполагаю, что то, что я спрашиваю, является общей «отправной точкой» для индексов, имеет ли смысл иметь конкретные индексы для конкретных часто запрашиваемых запросов и полей в предложениях WHERE или ORDER BY?

Эндрю Барбер
источник

Ответы:

27

Вы правы в том, что ваш пример запроса не будет использовать этот индекс.

Планировщик запросов рассмотрит использование индекса, если:

  • все поля, содержащиеся в нем, упоминаются в запросе
  • некоторые поля начинаются с начала

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

Итак, для вашего примера:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

он будет рассматривать такие индексы, как:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

но нет:

[name], [customerId], [dateCreated]

Если бы он нашел оба, [customerId]и [customerId], [dateCreated], [name]его решение предпочесть одно другому, будет зависеть от статистических показателей индекса, которые зависят от оценок баланса данных в полях. Если[customerId], [dateCreated] были определены, он должен предпочесть это двум другим, если вы не дадите конкретную подсказку об обратном.

В моем опыте также нередко можно видеть один индекс, определенный для каждого поля, хотя это редко бывает оптимальным, поскольку дополнительное управление, необходимое для обновления индексов при вставке / обновлении, и дополнительное пространство, необходимое для их хранения, теряется, когда половина они могут никогда не привыкнуть, но если ваша БД не будет перегружена при записи, производительность не будет сильно вонять даже при избыточных индексах.

Определенные индексы для частых запросов, которые в противном случае были бы медленными из-за сканирования таблиц или индексов, как правило, являются хорошей идеей, хотя не переусердствуйте, поскольку вы могли бы заменить одну проблему производительности на другую. [customerId], [dateCreated]Например, если вы определите индекс как индекс, помните, что планировщик запросов сможет использовать его для запросов, которые будут использовать индекс только в [customerId]случае его наличия . Хотя использование just [customerId]было бы несколько более эффективным, чем использование составного индекса, это можно было бы смягчить, если бы два индекса конкурировали за место в ОЗУ вместо одного (хотя, если весь ваш обычный рабочий набор легко помещается в ОЗУ, конкуренция за дополнительную память может не вопрос).

Дэвид Спиллетт
источник
+1; отличная информация, особенно напоминание (которое я склонен забывать!), что планировщик может использовать составной индекс в тех случаях, когда ему нужны только первые поля из него для запроса.
Эндрю Барбер
6

Чтобы ответить на ваш первоначальный вопрос, да, индексы должны быть разработаны вокруг запросов , а не только таблицы . Порядок полей в индексе жизненно важен. Разработка единого индекса, оптимального для нескольких запросов, сложнее, и вам придется идти на компромиссы.

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

Моя стратегия разработки индексов заключается в том, чтобы индексировать:

  • Поля, используемые в WHERE (в порядке селективности)
  • Поля, используемые в ORDER BY
  • Включите другие поля (при необходимости), чтобы создать индекс покрытия

Итак, для вашего примера:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Я, вероятно, разработал бы индекс для (CustomerID, dateCreated) INCLUDE (id, name). Этот покрывающий индекс означает, что запросу никогда не придется попадать в исходную таблицу, что значительно повышает производительность.

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

BradC
источник
+1 для «индексы должны быть разработаны вокруг запросов, а не только таблицы», и остальная часть ответа, например, отметив, что пример очень прост.
Эндрю Барбер