2011-01-24 12 views
7

Próbuję wyśledzić problem z zapytaniem, które mam. Zapytanie jest faktycznie generowane przez hibernację z HQL, ale wynikowy kod SQL nie spełnia oczekiwań. Modyfikacja SQL lekko daje prawidłowy wynik, ale nie jestem pewien, dlaczego modyfikacja powinna wprowadzić jakąkolwiek różnicę.Zachowanie łączenia krzyżowego (SQLServer 2008)

Original query (nie zwraca wiersze)

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 

Zmodyfikowane zapytanie - cross join zastępuje się przecinkiem (niejawny krzyża przyłączyć)

zwraca jeden wiersz

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 

mojego zrozumienia, co może być niepoprawny, to pisanie from Table1 a, Table2 b jest tym samym, co pisanie from Table 1 a cross join Table2 b. Więc nie rozumiem, dlaczego zapytania zwracają różne wyniki.

Czy jest coś wspólnego z interakcją między łączeniem krzyżowym a zewnętrznymi złączeniami w pierwszym zapytaniu, które to powoduje? Przyjrzałem się planom zapytań, a drugi plan zapytania wygląda rozsądnie. Pierwszy nie ma w ogóle zewnętrznych połączeń, co jest dziwne.

Jest na SQLServer 2008.

Odpowiedz

9

DOŁĄCZ ma wyższy priorytet niż przecinek, więc drugie stwierdzenie jest interpretowane jako (uwaga parens dodałam):

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 

Zobacz także: JOIN precendence rules per SQL-99

+0

Dzięki +1. W moim HQL użyłem COMMA, więc nie jestem pewien, dlaczego hibernacja renderowałaby CROSS JOIN. Zmieniłem klauzule "od", aby tabela "Okres" była ostatnia i działała poprawnie. Nadal powstaje połączenie krzyżowe, ale ponieważ ma ono pierwszeństwo, działa zgodnie z oczekiwaniami. –

+0

@Mike Podkreśla to szorstką krawędź używania RIGHT JOIN zamiast zmiany kolejności, aby użyć LEFT JOIN. Jeśli to zapytanie zostało przepisane, aby umieścić ważne tabele po lewej stronie (i na górze zapytania), cała sprawa UNION vs. przecinek zniknąłaby. – ErikE

+0

@Emtucifor - To prawda, niestety zapytanie to jest generowane przez niektóre Hibernate HQL i ze względu na jego naturę z wykorzystaniem relacji modelu obiektowego, a nie definiowanie dowolnych warunków łączenia, jest trudne do przepisania (a raczej nie wiem jak je przepisać!) –

0

Bez patrzenia na rzeczywiste plany danych i zapytań, powiedziałbym (ok, domyślam się), że ma to związek ze sposobem, w jaki optymalizator tworzy plany zapytań.

W pierwszym, jest bardziej lub mniej wyraźnie powiedział do „podjęcia pierwszej tabeli, krzyż dołączyć go z drugim, a następnie w prawo przyłączyć się trzeci, potem w prawo przyłączyć się do czwartego”

W sekundę , że sprzężenie krzyżowe jest (przynajmniej na mój sposób myślenia) domyślnie. Jest to "stara" składnia SQL od czasów, kiedy wszystkie sprzężenia zostały wykonane w klauzuli WHERE, co - moim zdaniem - oznacza, że ​​silnik bazy danych mógł sam wypracować kolejność, w jakiej tabele procesów. Innymi słowy, SQL nie otrzymuje konkretnej kolejności dołączania do tabel. (Z wewnętrznymi łączeniami i łączeniami krzyżowymi nie ma to znaczenia, ale z zewnętrznymi łączeniami może to zrobić ogromną różnicę.)

... Preferuję odpowiedź Joe Joe (upvoted), ponieważ jest to technicznie poprawne. I tak rzucam to na własny rachunek, tylko ze względu na szczegóły.