2011-01-24 12 views
7

He estado intentando localizar un problema con una consulta que tengo. La consulta se genera realmente por hibernación de HQL pero el SQL resultante no hace lo que esperaba. Modificar el SQL produce ligeramente el resultado correcto, pero no estoy seguro de por qué la modificación debería marcar la diferencia.Comportamiento de combinación cruzada (SQLServer 2008)

búsqueda original (no devuelve ninguna fila)

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 

Modificado consulta - combinación cruzada reemplazado por una coma (cruz implícita unirse a)

devuelve una fila

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 

mi entendimiento, el cual puede ser incorrecto es que escribir from Table1 a, Table2 b es lo mismo que escribir from Table 1 a cross join Table2 b. Entonces no entiendo por qué las consultas arrojan resultados diferentes.

¿Hay algo que ver con la interacción entre la unión cruzada y las uniones externas en la primera consulta que causa esto? Miré los planes de consulta y el segundo plan de consulta parece razonable. El primero no tiene uniones externas en absoluto, lo cual es extraño.

Esto está en SQL Server 2008.

Respuesta

9

JOIN tiene una prioridad más alta que una coma, por lo que su segunda declaración se interpreta como (nótese el parens he añadido):

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 

Ver también: JOIN precendence rules per SQL-99

+0

Gracias +1. En mi HQL he usado un COMMA, así que no estoy seguro de por qué Hibernate convertiría un CROSS JOIN en su lugar. Cambié las cláusulas de from para que la tabla de Período fuera la última y funcionó correctamente. Todavía produjo la unión cruzada, pero como es la última en la precedencia, funciona como se esperaba. –

+0

@Mike Esto resalta el borde áspero de usar RIGHT JOIN en lugar de reordenar para usar LEFT JOIN. Si esta consulta se reescribió para colocar las tablas importantes a la izquierda (y en la parte superior de la consulta), la cosa entera de la UNIÓN vs. las comas habría desaparecido. – ErikE

+0

@Emtucifor - Cierto, desafortunadamente esta consulta es generada por Hibernate HQL y debido a la naturaleza de ella usando las relaciones del modelo de objetos en lugar de definir condiciones de combinación arbitrarias es difícil reescribir (¡o más bien, no sé cómo reescribirla!) –

0

Sin mirar los datos reales y los planes de consulta, diría (vale, supongo) que tiene que ver con la forma en que el optimizador construye los planes de consulta.

En la primera, que es más o menos explícitamente dijo que "tomar la primera tabla, la cruz se unen con el segundo, y luego unirse a la derecha en la tercera, y luego unirse a la derecha en el cuarto"

En el segundo , esa combinación cruzada es (al menos a mi modo de pensar) implícita. Esta es la sintaxis SQL "antigua" de los días en que se realizaban todas las uniones en la cláusula WHERE, lo que, de nuevo, a mi modo de ver, significa que el motor de base de datos era libre de resolver por sí mismo el orden en el que tablas de proceso. O, en otras palabras, SQL no se está dando un orden específico en el que unir tablas. (Con combinaciones internas y combinaciones cruzadas, no hace ninguna diferencia, pero con combinaciones externas, puede hacer una gran diferencia.)

... Prefiero la respuesta de @Joe (votada), ya que es técnicamente precisa. La estoy lanzando de todos modos solo por el detalle.

Cuestiones relacionadas