Насколько важен порядок столбцов в индексах? - PullRequest
147 голосов
/ 19 февраля 2010

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

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

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

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

Ответы [ 5 ]

177 голосов
/ 19 февраля 2010

Посмотрите на индекс, подобный этому:

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

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

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

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

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

114 голосов
/ 19 февраля 2010

Порядок столбцов является критическим. Теперь, какой порядок правильный, зависит от того, как вы собираетесь запросить его. Индекс может использоваться для точного поиска или сканирования диапазона. Точный поиск - это когда заданы значения для всех столбцов в индексе, и запрос попадает точно в строку, в которой заинтересован. Для запросов порядок столбцов не имеет значения. Сканирование диапазона - это когда указаны только некоторые столбцы, и в этом случае порядок становится важным. SQL Server может использовать индекс для сканирования диапазона только в том случае, если указан крайний левый столбец, и только в том случае, если указан следующий крайний левый столбец и т. Д. Если у вас есть индекс на (A, B, C), его можно использовать для сканирования диапазона для A=@a, для A=@a AND B=@b, но , а не для B=@b, для C=@c или B=@b AND C=@c , Случай A=@a AND C=@c является смешанным, так как в части A=@a будет использоваться индекс, но C=@c нет (запрос отсканирует все значения B для A=@a, не пропустит C=@c) , Другие системы баз данных имеют так называемый оператор «пропустить сканирование», который может использовать некоторые преимущества внутренних столбцов в индексе, когда внешние столбцы не указаны.

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

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

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

40 голосов
/ 22 августа 2016

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

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

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

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

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 = '~'; 

... Оба они используют штраф индекса и оба имеют одинаковую стоимость.

enter image description here

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

enter image description here

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

Для вышеприведенного запроса 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 

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

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

30 голосов
/ 19 февраля 2010

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

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

  • Адрес
  • Город
  • Состояние

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

2 голосов
/ 06 февраля 2019

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

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

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

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

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

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

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

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

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

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

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