Поведение перекрестного соединения (SQLServer 2008) - PullRequest
7 голосов
/ 24 января 2011

Я пытался отследить проблему с помощью моего запроса.Запрос фактически генерируется hibernate из HQL, но полученный SQL не делает то, что я ожидаю.Небольшое изменение SQL дает правильный результат, но я не уверен, почему изменение должно иметь какое-либо значение.

Исходный запрос (не возвращает строк)

select sched.id, max(txn.dttm), acc.id
from PaymentSchedulePeriod sched 
cross join PaymentSchedulePayment pay
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id 
where sched.accountFk=acc.id 
group by sched.id, acc.id

Измененный запрос - заменено перекрестное соединениечерез запятую (неявное перекрестное соединение)

Возвращает одну строку

select sched.id, max(txn.dttm), acc.id
from PaymentSchedulePeriod sched 
,PaymentSchedulePayment pay
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id 
where sched.accountFk=acc.id 
group by sched.id, acc.id

Насколько я понимаю, неправильным может быть то, что запись from Table1 a, Table2 b такая же, как запись from Table 1 a cross join Table2 bПоэтому я не понимаю, почему запросы возвращают разные результаты.

Это как-то связано с взаимодействием между перекрестным соединением и внешними объединениями в первом запросе, которое вызывает это?Я посмотрел на планы запроса, и второй план запроса выглядит разумным.У первого нет внешних соединений вообще, что странно.

Это на SQLServer 2008.

Ответы [ 2 ]

9 голосов
/ 24 января 2011

JOIN имеет более высокий приоритет, чем COMMA, поэтому ваше второе утверждение интерпретируется как (обратите внимание на добавленные мной символы):

select sched.id, max(txn.dttm), acc.id
from PaymentSchedulePeriod sched 
,(PaymentSchedulePayment pay
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id)
where sched.accountFk=acc.id 
group by sched.id, acc.id

См. Также: Правила приоритета JOIN для SQL-99

0 голосов
/ 24 января 2011

Не глядя на фактические данные и планы запросов, я бы сказал (хорошо, наверное), что это связано с тем, как оптимизатор создает планы запросов.

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

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

... Я предпочитаю ответ @ Джо (с подтверждением), поскольку он технически точен.Я в любом случае бросаю это только ради деталей.

...