Индексы для внутренних объединений с предложением where - PullRequest
4 голосов
/ 05 января 2010

Если бы у меня был следующий запрос:

select some cols 
   from tbl_a
INNER JOIN tbl_b ON tbl_a.orderNumber = tbl_b.orderNumber
   where tlb_b.status = 'XX'

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

Ответы [ 7 ]

7 голосов
/ 05 января 2010
  1. Вы добавляете tbl_b для добавления статуса после номер заказа: create clustered index ... on tbl_b(orderNumber, status). Для запроса выше не будет заметной разницы. Плану все равно придется сканировать tbl_b от начала до конца и сопоставлять каждый номер заказа в tbl_a (возможно, объединение слиянием).

  2. Вы расширяете tbl_b, чтобы добавить статус до номера заказа: create clustered index ... on tbl_b (status, orderNumber). Теперь есть огромная разница. План может выполнить сканирование диапазона для tbl_b, чтобы получить только те, которые имеют статус «xx», и сопоставить tbl_a только с соответствующим порядковым номером, используя соединение с вложенным циклом.

Размещение столбца с низкой избирательностью (например, «статус») в качестве крайнего левого ключа в индексе, как правило, хорошо. И создание строки, подобной 'status', в крайнем левом столбце кластерного индекса также обычно является хорошей идеей, поскольку физически группирует записи с одинаковым статусом. Обратите внимание, что это повлияет на все запросы. Вы также потеряете прямой доступ по orderNumber, если статус не указан, вам придется добавить некластеризованный индекс только для orderNumber, чтобы покрыть это (обычно это некластерный индекс PK).

Я сделал все эти комментарии без знания вашей фактической мощности и избирательности. Если количество элементов tbl_a и tbl_b сильно искажено, то все может быть иначе. Например. если tbl_a имеет 10 записей с 10 различными номерами заказов, а tbl_b имеет 10M записей с 10M номерами заказов, то мой вариант 2 не будет иметь большого значения, поскольку план всегда будет выбирать сканирование tbl_a при поиске диапазона поиска в tbl_b 10 раз.

2 голосов
/ 05 января 2010

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

Причина в том, что кластерный индекс представляет физический порядок данных на диске. Если вы добавляете составной столбец, таблицу (в некоторых / большинстве случаев) необходимо будет повторно отсортировать на диске при добавлении заказа или обновлении статуса. Это очень дорого из-за ввода-вывода и увеличения времени блокировки.

2 голосов
/ 05 января 2010

Добавление статуса к кластерному индексу позволит SQL Server более эффективно разрешать предложение where. SQL Server может сначала найти все индексы в определенном состоянии из индекса и выполнить объединение на основе этого. Чтобы это работало, статус должен быть первым столбцом в индексе:

(status, orderNumber)

Обратите внимание, что если вы расширите первичный ключ таким способом, столбец orderNumber больше не будет гарантированно уникальным. Так что лучше добавить это как отдельный индекс.

Насколько полезен отдельный индекс, зависит от избирательности статуса. Если вы ищете «Сбой» и только 1% ваших заказов имеют этот статус, индекс будет очень полезен. Если состояние не очень избирательное, SQL Server может вообще не использовать новый индекс.

2 голосов
/ 05 января 2010

Да, вполне возможно. Это называется индексом покрытия. Весь запрос может быть обработан из индекса, вообще не обращаясь к tbl_b.

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

1 голос
/ 05 января 2010

Документация MS рекомендует:

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

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

1 голос
/ 05 января 2010

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

Также есть возможность создания второго индекса (номер заказа, статус). Вы, вероятно, выиграете еще больше, если создадите индекс (status, ordernumber).

1 голос
/ 05 января 2010

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

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