2010-01-04 2 views
3

Если бы я имел следующий запрос:Индексы для внутренних соединений с тем, где пункт

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

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

+0

Это зависит. Являются ли первичными (или уникальными) ограничениями? Если нет, какова мощность (частота появления отдельных значений) каждой из соединенных столбцов? Какова мощность столбца tbl_b.status? ... да, кажется очевидным, что происходит, но я решил не делать предположений о данных других людей в этом десятилетии. –

ответ

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

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

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

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

+0

Спасибо за ответ. Если я создаю только кластерный индекс orderNumber, могу ли добавить некластеризованный индекс со статусом, а не в состояние, orderNumber (поскольку кластерный индекс включен в некластеризованный индекс)? – SuperCoolMoss

+0

Некластеризованный индекс (статус) будет малопригодным. Вы должны сделать некластеризованный индекс (статус, orderNumber) imho. –

1

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

2

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

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

+0

Индекс покрытия будет включать в себя «некоторые cols», а также – Andomar

+1

Кроме того, кластеризованный индекс определяется индексом покрытия :) – Andomar

+0

@Andomar (2-й комментарий) - нет, я так не думаю. Индекс «покрытия» распространяется только в контексте конкретного запроса, так как индекс «охватывает» все столбцы из этой таблицы, используемые в запросе. –

1

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

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

2

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

(status, orderNumber) 

Обратите внимание, что если вы расширяете первичный ключ таким образом, столбец ORDERNUMBER больше не guarantueed быть уникальным. Поэтому лучше добавить это как отдельный индекс.

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

+0

+1 просто быстрая заметка о том, что даже при очень низкой избирательности статус в левой позиции по-прежнему будет использоваться. Даже если есть только два возможных значения для статуса (скажем, 0,1), тогда индекс (status, orderNumber) на tbl_b все равно уменьшит номера заказов кандидата пополам, поэтому план, скорее всего, выберет его. Я намеренно игнорирую влияние «некоторых cols» (т. Е. На покрытие списка проекций), потому что это, по-моему, другая тема. –

1

MS documentation рекомендует:

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

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

2

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

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