Насколько важен порядок столбцов в индексах?

Я слышал, что вы должны поместить столбцы, которые будут наиболее избирательными в начале объявления индекса. Пример:

CREATE NONCLUSTERED INDEX MyINDX on Table1
(
   MostSelective,
   SecondMost,
   Least
)

Во-первых, это то, что я говорю правильно? Если это так, я могу увидеть большие различия в производительности, изменив порядок столбцов в моем индексе или это скорее практика "приятно делать"?

Причина, по которой я спрашиваю, заключается в том, что после помещения запроса через DTA мне рекомендуется создать индекс, в котором почти все те же столбцы, что и существующий, только в другом порядке. Я рассматривал возможность добавления отсутствующих столбцов в существующий индекс и называть его хорошим. Мысли?

Ответ 1

Посмотрите на такой индекс:

Cols
  1   2   3
-------------
|   | 1 |   |
| A |---|   |
|   | 2 |   |
|---|---|   |
|   |   |   |
|   | 1 | 9 |
| B |   |   |
|   |---|   |
|   | 2 |   |
|   |---|   |
|   | 3 |   |
|---|---|   |

Посмотрите, как ограничение на A сначала, так как ваш первый столбец устраняет больше результатов, чем ограничивает ваш второй столбец первым? Это проще, если вы посмотрите, как должен проходить обход индекса, столбец 1, затем столбец 2 и т.д.... вы видите, что отсечение большинства результатов в первом прыжке делает второй шаг намного быстрее.

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

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

Короче: нет, это не для показа, есть реальные преимущества в производительности.

Ответ 2

Порядок столбцов критический. Теперь какой порядок правилен, это зависит от того, как вы собираетесь его запрашивать. Индекс может использоваться для точного поиска или сканирования диапазона. Точный поиск - это когда значения для всех столбцов в индексе указаны и запрос попадает точно в строку. Интересно, что порядок столбцов не имеет значения. Сканирование диапазона - это когда указаны только некоторые столбцы, и в этом случае, когда порядок становится важным. SQL Server может использовать индекс для сканирования диапазона, только если указан крайний левый столбец, а затем только если указан следующий левый столбец и т.д. Если у вас есть индекс на (A, B, C), он может использоваться для сканирования диапазона для [email protected], для [email protected] AND [email protected], но не для [email protected], для [email protected] и [email protected] AND [email protected]. Случай [email protected] AND [email protected] смешанный, так как в разделе [email protected] будет использоваться индекс, но [email protected] not (запрос будет сканировать все значения B для [email protected], не будет пропускать до [email protected]), Другие системы баз данных имеют так называемый оператор "skip scan", который может использовать некоторые преимущества внутренних столбцов в индексе, если внешние столбцы не указаны.

С учетом этих знаний вы снова можете взглянуть на определения индекса. Индекс на (MostSelective, SecondMost, Least) будет эффективен только при указании столбца MostSelective. Но, будучи наиболее избирательным, актуальность внутренних столбцов будет быстро ухудшаться. Очень часто вы обнаружите, что лучший индекс находится на (MostSelective) include (SecondMost, Least) или на (MostSelective, SecondMost) include (Least). Поскольку внутренние столбцы менее релевантны, размещение столбцов с низкой степенью избирательности в таких правильных положениях в индексе делает их не чем иным, как шумом для поиска, поэтому имеет смысл перемещать их из промежуточных страниц и сохранять их только на страницах листа, для цели покрытия запросов. Другими словами, переместите их в INCLUDE. Это становится более важным, так как увеличивается размер столбца Least. Идея заключается в том, что этот индекс может приносить пользу только запросам, которые указывают MostSelective как точное значение или диапазон, а этот столбец является наиболее избирательным, и он в значительной степени ограничивает строки-кандидаты.

С другой стороны, индекс на (Least, SecondMost, MostSelective) может показаться ошибкой, но на самом деле это довольно мощный индекс. Поскольку он имеет столбец Least в качестве своего внешнего запроса, его можно использовать для запросов, которые должны агрегировать результаты на столбцах с низкой степенью избирательности. Такие запросы распространены в OLAP и аналитических хранилищах данных, и именно в таких индексах для них очень хороший случай. Такие индексы фактически делают отличные кластерные индексы, именно потому, что они организуют физический макет для больших фрагментов связанных строк (то же самое значение Least, которое обычно указывает какую-то категорию или тип), и они облегчают аналитические запросы.

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

Ответ 3

Как говорит Ремус, это зависит от вашей рабочей нагрузки.

Я хочу обратиться к вводящему в заблуждение аспекту принятого ответа.

Для запросов, выполняющих поиск по равенству во всех столбцах в индексе, существенной разницы нет.

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

CREATE TABLE Table1(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);
CREATE TABLE Table2(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);

CREATE NONCLUSTERED INDEX MyINDX on Table1(MostSelective,SecondMost,Least);
CREATE NONCLUSTERED INDEX MyINDX2 on Table2(Least,SecondMost,MostSelective);

INSERT INTO Table1 (MostSelective, SecondMost, Least)
output inserted.* into Table2
SELECT TOP 26 REPLICATE(CHAR(number + 65),800), number/5, '~'
FROM master..spt_values
WHERE type = 'P' AND number >= 0
ORDER BY number;

Теперь сделаем запрос к обеим таблицам...

SELECT *
FROM   Table1
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~';

SELECT *
FROM   Table2
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~'; 

... Оба из них используют индексный тон, и оба они имеют одинаковые затраты.

введите описание изображения здесь

Искусство ASCII в принятом ответе не является фактически структурированием индексов. Страницы индекса для таблицы 1 представлены ниже (щелкните изображение, чтобы открыть его в полном размере).

введите описание изображения здесь

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

Для запроса выше SQL Server не заботится об избирательности столбцов. Он выполняет двоичный поиск корневой страницы и обнаруживает, что Ключ (PPP...,3,~ ) - это >=(JJJ...,1,~ ) и < (SSS...,3,~ ), поэтому он должен читать страницу 1:118. Затем он выполняет двоичный поиск записей на этой странице и обнаруживает, что листовая страница перемещается вниз.

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

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

Например, если рабочая нагрузка содержит запросы обеих следующих форм.

SELECT * ... WHERE  MostSelective = 'P'

SELECT * ...WHERE Least = '~'

Указанные выше индексы не покрывают ни один из них. MostSelective достаточно избирательно, чтобы сделать план с поиском и поиском стоящим, но запрос с Least не является.

Однако этот сценарий (не охватывающий индекс ищет подмножество ведущего столбца (ов) составного индекса) - это только один возможный класс запросов, которому может помочь индекс. Если вы никогда не выполняете поиск по MostSelective самостоятельно или комбинацию MostSelective, SecondMost и всегда выполняете поиск по комбинации из трех столбцов, то это теоретическое преимущество бесполезно для вас.

Обратные запросы, такие как

SELECT MostSelective,
       SecondMost,
       Least
FROM   Table2
WHERE  Least = '~'
ORDER  BY SecondMost,
          MostSelective 

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

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

Ответ 4

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

Правильно. Индексы могут быть композитами, состоящими из нескольких столбцов, и порядок важен из-за самого левого принципа. Причина в том, что база данных проверяет список слева направо и должна найти соответствующую ссылку столбца, соответствующую определенному порядку. Например, имея индекс в таблице адресов с столбцами:

  • Адрес
  • Город
  • Государство

Любой запрос, использующий столбец address, может использовать индекс, но если запрос имеет только ссылки city и/или state - индекс не может использоваться. Это связано с тем, что в крайнем левом столбце не указаны ссылки. Производительность запроса должна рассказать вам, что является оптимальным - отдельные индексы или несколько композитов с разными заказами. Хорошо читайте: The Tipping Point, автор Кимберли Трипп

Ответ 5

Все ответы неверны.

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

Вот простой мыслительный процесс: по сути, индекс - это объединение задействованных столбцов.

Если дать такое обоснование, то единственное различие заключается в сравнении двух "строк", которые отличаются раньше и позже в строке. Это крошечная часть общей стоимости. Не существует "первого прохода/второго прохода", как указано в одном ответе.

Итак, какой порядок следует использовать?

  1. Начните с столбца (-ов), протестированных с =, в любом порядке.
  2. Затем выберите один столбец диапазона.

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

WHERE deleted = 0  AND  the_datetime > NOW() - INTERVAL 7 DAY
INDEX(deleted, the_datetime)

Перестановка порядка в индексе будет иметь его полностью игнорировать deleted.

(Есть намного больше правил для заказа столбцов.)