Индекс производительности по ON против ГДЕ

26

У меня две таблицы

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Эти таблицы имеют некластеризованный индекс на (Id, Date)

И я присоединяюсь к этим таблицам

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Это также можно записать как

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

У меня вопрос, какой из этих двух запросов дает лучшую производительность и почему? Или они равны?

Эрик Бергштедт
источник
1
У вас действительно есть переменная @table с некластеризованным индексом, который охватывает все поля, и без кластерного индекса? или это просто упрощение?
Ремус Русану
1
Это крайнее упрощение
Эрик Бергштедт

Ответы:

32

Производительность будет такой же. Оптимизатор распознает это и создаст тот же план.

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

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

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

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Дает эти планы выполнения

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

Том V - Команда Моника
источник
Я согласен, первую форму легче читать, и поэтому я рад, что они равны. Я буду использовать эту форму только в будущем.
Эрик Бергштедт
@ErikBergstedt Я отредактировал свой ответ, вы сможете довольно легко проверить это для своего собственного набора данных и структуры таблицы, если вы посмотрите на планы выполнения
Том V - Team Monica
Да, я сделал. Спасибо. Я искал только второе мнение, так как я не нашел никакого существующего ответа.
Эрик Бергштедт
Примечание: они ТОЛЬКО равны, если это INNER JOIN. Если вы добавите, OUTER JOINто они, безусловно, не то же самое.
Кеннет Фишер
22

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

Я склонен ставить условия, ссылающиеся на обе таблицы в, ONи условия, ссылающиеся только на одну таблицу в WHERE.

Однако на OUTER JOINSперемещение условий может повлиять семантика.

Мартин Смит
источник
7

В простых случаях это будет то же самое. Однако я видел, что очень сложные запросы с несколькими объединениями имеют существенно разные планы. Недавняя работа, над которой я работал, началась с таблицы, в которой около 6 миллионов строк объединены с примерно 20 различными таблицами. Только первое соединение с этой таблицей было внутренним объединением, все остальные были оставлены внешними объединениями. Фильтр в предложении where был параметризован примерно так:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Этот фильтр был использован позже в плане, а не ранее. Когда я переместил эти условия в первое внутреннее объединение, план кардинально изменился, так как фильтр был применен на раннем этапе в плане, чтобы ограничить набор результатов, а мой ЦП и истекшее время сократились примерно на 310%. Так что, как и во многих вопросах SQL Server, это зависит.

Джаред Карни
источник
2
Не могли бы вы добавить больше деталей - возможно, скриншоты диаграмм плана выполнения - поскольку ваш ответ, кажется, противоречит всем остальным?
Кенни Эвитт
2
План показывал тайм-аут оптимизатора?
Мартин Смит
Как загрузка процессора может снизиться более чем на 100%?
Майкл Грин
2

В общем, то, куда вы помещаете фильтры, имеет значение.
В то время как Том V говорит, что Оптимизатор распознает, что запросы одинаковы, и предлагает один и тот же план, это не всегда так. Это зависит от того, какая у вас версия SQL, насколько сложен ваш запрос и насколько важен для всего пакета Оптимизатор определяет запрос.

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

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

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

Том Эверс
источник
1

В обычных условиях условия фильтрации могут быть указаны либо в предложениях WHERE, либо в JOIN. Я склонен помещать фильтры в поле WHERE, если только не может быть затронут приоритет OUTER JOIN (см. Ниже) или если фильтр очень специфичен для этой таблицы (например, TYPE = 12 для указания определенного подмножества строк в таблице).

С другой стороны, предложения ON и WHERE могут использоваться для указания условий соединения (в отличие от условий фильтрации). Пока вы используете только ВНУТРЕННИЕ объединения, все равно не будет иметь значения, что вы используете при обычных обстоятельствах.

Однако, если вы используете соединения OUTER, это может иметь большое значение. Если, например, вы указываете OUTER JOIN между двумя таблицами (t1 и t2), но затем в предложении WHERE продолжаете указывать отношение eqijoin между таблицами (например, t1.col = t2.col), вы просто преобразовал НАРУЖНОЕ объединение в ВНУТРЕННЕЕ объединение! Это связано с тем, что WHERE может использоваться для указания эквиджоин (или, может быть, даже OUTER join, в зависимости от версии, с использованием устаревшего синтаксиса * =) без использования предложения ON, и когда WHERE указывает внутреннее эквайоин между таблицами, он переопределяет OUTER ПРИСОЕДИНЯЙТЕСЬ (если есть).

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

McB2K3
источник
-1

С INNER JOINs это проблема стиля.

Тем не менее, это становится намного интереснее с OUTER JOIN. Вы должны изучить различия между запросами с OUTER JOIN и условиями как в предложении ON, так и в предложении WHERE. Набор результатов не всегда одинаков. Есть, например,

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

такой же как

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL
Шон Редмонд
источник
8
Если результат отличается (что это, конечно,), какой смысл сравнивать производительность?
ypercubeᵀᴹ