Extraño plan ejecución

25/08/2006 - 12:19 por Alvaro Mosquera | Informe spam
¿ Por qué en una query que tiene un left join, el plan de ejecución ejecuta
un inner join ?.
Obviamente los resultados no son los correctos.

Adjunto la query y el plan de ejecución.

La query

select c.codigoproducto,d.codigoproducto
from componentes c
left outer join historicodosificaciones d on c.codigoformula =
d.codigoformula and c.extension = d.extension and
c.codigoproducto = d.codigoproducto
where c.codigoformula = '412761' and c.extension = '6150' and d.diario =
'24/08/2006' and d.nromezcladia = 107

Plan de ejecución

|--Hash Match(Inner Join,
HASH:([d].[CodigoProducto])=([c].[CodigoProducto]),
RESIDUAL:([d].[CodigoProducto]=[c].[CodigoProducto]))
|--Clustered Index
Seek(OBJECT:([Trazas].[dbo].[HistoricoDosificaciones].[IX_HistoricoDosificaciones]
AS [d]), SEEK:([d].[Diario]='Ago 24 2006 12:00AM' AND
[d].[NroMezclaDia]7), WHERE:([d].[Extension]='6150' AND
[d].[CodigoFormula]='412761') ORDERED FORWARD)
|--Clustered Index
Scan(OBJECT:([Trazas].[dbo].[Componentes].[PK_Componentes] AS [c]),
WHERE:([c].[CodigoFormula]='412761' AND [c].[Extension]='6150'))

Preguntas similare

Leer las respuestas

#6 Alejandro Mesa
25/08/2006 - 22:31 | Informe spam
Hola Eladio,

Tu respuesta fue:

>> al aplicar un predicado where "inconscientemente" estás convirtiendo la
>> consulta en INNER JOIN.



Coincido contigo en esto.

>> para ello en las columnas incluidas en el predicado del alias d deberías
>> añadir or d.columna is null



No concuerdo con esto.

El filtro debe pasarlo junto al "join" y no en la clausula "where". Si es
que el espera ver las filas como indique.

Por otro lado, en el segundo grupo de queries, el predicado "od.OrderID is
null" no es considerado porque OrderID es la foreign key, y por lo tanto los
valores nulos ya están descartado en la operación INNER JOIN entre Orders y
[Order Details] donde OrderID es clave primaria en la tabla Orders.



Se me fue (copy y paste). Debio ser:

set showplan_text on
go

select
oh.*, od.*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
od.orderid = 10250

select
oh.*, od.*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
and od.orderid = 10250
go

De todas maneras puedes chequear que el plan de ejecucion sera el mismo sin
importar donde pones el filtro extra (od.orderid = 10250), puedes ponerlo en
el join o en la clausula "where". Lo mismo no aplica cuando usamos "outer
joins".


Saludos,

Alejandro Mesa

"Eladio Rincón" wrote:

Hola Alejandro,

no entiendo que quieres decir con "Concuerdo con la respuesta, pero no con
la solución".

Entiendo que Alvaro quiere aplicar el left join, y ha fastidiado la consulta
incluyendo el predicado where por una columna que antes no obligaba a
incluir los valores no nulos.

Por otro lado, en el segundo grupo de queries, el predicado "od.OrderID is
null" no es considerado porque OrderID es la foreign key, y por lo tanto los
valores nulos ya están descartado en la operación INNER JOIN entre Orders y
[Order Details] donde OrderID es clave primaria en la tabla Orders.

Saludos,

Eladio Rincón,


Visita mi página web
Artículos, recursos y trucos de SQL Server 2000 y 2005
http://www.siquelnet.com


"Alejandro Mesa" wrote in message
news:
> Hola Eladio,
>
> Concuerdo con la respuesta, pero no con la solución. Yo no se a que se
> refiere Alvaro cuando dice "Obviamente los resultados no son los
> correctos".
> Si se refiere a que se espera en el resultado las filas de la tabla
> [componentes] aunque no exista una fila que mache la condicion de union en
> la
> tabla [historicodosificaciones] (para eso usamos los operadores "outer
> join"), entonces las condiciones que el usa en la clausula "where" deben
> ser
> aplicadas como parte de la condicion de union. Si la expresion logica se
> pone
> en la clausula "where", entonces el significado cambia (esto no aplica
> cuando
> usamos el operador "inner join") ya que estariamos filtrando el resultado
> de
> la union en vez de aplicar operador y condicion de union al mismo tiempo.
> Veamos un caso practico. Si ejecutamos la siguiente sentencia en QA,
> veremos
> que el resultado no es el mismo y eso lo podemos ver tambien en el plan de
> ejecucion.
>
> select
> oh.*, od.*
> from
> dbo.orders as oh
> left outer join
> dbo.[order details] as od
> on oh.orderid = od.orderid
> where
> od.orderid = 10250 or od.orderid is null
>
> select
> oh.*, od.*
> from
> dbo.orders as oh
> left outer join
> dbo.[order details] as od
> on oh.orderid = od.orderid
> and od.orderid = 10250
> go
>
> Veamos los planes de ejecucion:
>
> |--Filter(WHERE:([od].[OrderID]250 OR [od].[OrderID]=NULL))
> |--Merge Join(Left Outer Join,
> MERGE:([oh].[OrderID])=([od].[OrderID]),
> RESIDUAL:([oh].[OrderID]=[od].[OrderID]))
> |--Clustered Index
> Scan(OBJECT:([northwind].[dbo].[Orders].[PK_Orders] AS [oh]), ORDERED
> FORWARD)
> |--Clustered Index Scan(OBJECT:([northwind].[dbo].[Order
> Details].[PK_Order_Details] AS [od]), ORDERED FORWARD)
>
>
> |--Nested Loops(Left Outer Join, WHERE:([oh].[OrderID]250))
> |--Clustered Index
> Scan(OBJECT:([northwind].[dbo].[Orders].[PK_Orders] AS [oh]))
> |--Table Spool
> |--Clustered Index Seek(OBJECT:([northwind].[dbo].[Order
> Details].[PK_Order_Details] AS [od]), SEEK:([od].[OrderID]250) ORDERED
> FORWARD)
>
>
> Esto no pasa cuando usamos el operador "inner join". En este caso SQL
> Server
> escoje el mismo plan de ejecucion.
>
> set showplan_text on
> go
>
> select
> oh.*, od.*
> from
> dbo.orders as oh
> inner join
> dbo.[order details] as od
> on oh.orderid = od.orderid
> where
> od.orderid = 10250 or od.orderid is null
>
> select
> oh.*, od.*
> from
> dbo.orders as oh
> inner join
> dbo.[order details] as od
> on oh.orderid = od.orderid
> and od.orderid = 10250
> go
>
> set showplan_text off
> go
>
> |--Nested Loops(Inner Join)
> |--Clustered Index
> Seek(OBJECT:([northwind].[dbo].[Orders].[PK_Orders] AS [oh]),
> SEEK:([oh].[OrderID]250) ORDERED FORWARD)
> |--Clustered Index Seek(OBJECT:([northwind].[dbo].[Order
> Details].[PK_Order_Details] AS [od]), SEEK:([od].[OrderID]250) ORDERED
> FORWARD)
>
>
> |--Nested Loops(Inner Join)
> |--Clustered Index
> Seek(OBJECT:([northwind].[dbo].[Orders].[PK_Orders] AS [oh]),
> SEEK:([oh].[OrderID]250) ORDERED FORWARD)
> |--Clustered Index Seek(OBJECT:([northwind].[dbo].[Order
> Details].[PK_Order_Details] AS [od]), SEEK:([od].[OrderID]250) ORDERED
> FORWARD)
>
>
> Saludos,
>
> Alejandro Mesa
>
>
> "Eladio Rincón" wrote:
>
>> Hola,
>>
>> al aplicar un predicado where "inconscientemente" estás convirtiendo la
>> consulta en INNER JOIN.
>>
>> para ello en las columnas incluidas en el predicado del alias d deberías
>> añadir or d.columna is null
>>
>>
>> mira el siguiente ejemplo:
>>
>>
>> use tempdb
>> go
>> drop table dbo.t
>> go
>> create table dbo.t (id1 int, id2 int)
>> go
>> insert dbo.t select 1, 1
>> insert dbo.t select 2, null
>> insert dbo.t select 3, 0
>> go
>>
>> select *
>> from dbo.t t1
>> left join dbo.t t2
>> on t1.id1 = t2.id2
>> go
>>
>> select *
>> from dbo.t t1
>> left join dbo.t t2
>> on t1.id1 = t2.id2
>> where t2.id2 = 1
>> go
>>
>> select *
>> from dbo.t t1
>> left join dbo.t t2
>> on t1.id1 = t2.id2
>> where t2.id2 = 1 or t2.id2 is null
>>
>>
>>
>> Saludos,
>>
>> Eladio Rincón,
>> http://www.siquelnet.com
>>
>> "Alvaro Mosquera" wrote in
>> message news:
>> >¿ Por qué en una query que tiene un left join, el plan de ejecución
>> >ejecuta
>> > un inner join ?.
>> > Obviamente los resultados no son los correctos.
>> >
>> > Adjunto la query y el plan de ejecución.
>> >
>> > La query
>> >
>> > select c.codigoproducto,d.codigoproducto
>> > from componentes c
>> > left outer join historicodosificaciones d on c.codigoformula > >> > d.codigoformula and c.extension = d.extension and
>> > c.codigoproducto = d.codigoproducto
>> > where c.codigoformula = '412761' and c.extension = '6150' and
>> > d.diario
>> > > >> > '24/08/2006' and d.nromezcladia = 107
>> >
>> > Plan de ejecución
>> >
>> > |--Hash Match(Inner Join,
>> > HASH:([d].[CodigoProducto])=([c].[CodigoProducto]),
>> > RESIDUAL:([d].[CodigoProducto]=[c].[CodigoProducto]))
>> > |--Clustered Index
>> > Seek(OBJECT:([Trazas].[dbo].[HistoricoDosificaciones].[IX_HistoricoDosificaciones]
>> > AS [d]), SEEK:([d].[Diario]='Ago 24 2006 12:00AM' AND
>> > [d].[NroMezclaDia]7), WHERE:([d].[Extension]='6150' AND
>> > [d].[CodigoFormula]='412761') ORDERED FORWARD)
>> > |--Clustered Index
>> > Scan(OBJECT:([Trazas].[dbo].[Componentes].[PK_Componentes] AS [c]),
>> > WHERE:([c].[CodigoFormula]='412761' AND [c].[Extension]='6150'))
>> >
>> >
>>
>>
>>



Respuesta Responder a este mensaje
#7 Alvaro Mosquera
28/08/2006 - 08:21 | Informe spam
Lo resultados no son correctos porque la tabla componentes tiene un registro
que no existe en historicodosificaciones y al transformarse la query en un
inner join, no lo devuelve.

"Alejandro Mesa" escribió:

Alvaro,

Por que dices que los resultados no son los correctos?


AMB

"Alvaro Mosquera" wrote:

> ¿ Por qué en una query que tiene un left join, el plan de ejecución ejecuta
> un inner join ?.
> Obviamente los resultados no son los correctos.
>
> Adjunto la query y el plan de ejecución.
>
> La query
>
> select c.codigoproducto,d.codigoproducto
> from componentes c
> left outer join historicodosificaciones d on c.codigoformula =
> d.codigoformula and c.extension = d.extension and
> c.codigoproducto = d.codigoproducto
> where c.codigoformula = '412761' and c.extension = '6150' and d.diario =
> '24/08/2006' and d.nromezcladia = 107
>
> Plan de ejecución
>
> |--Hash Match(Inner Join,
> HASH:([d].[CodigoProducto])=([c].[CodigoProducto]),
> RESIDUAL:([d].[CodigoProducto]=[c].[CodigoProducto]))
> |--Clustered Index
> Seek(OBJECT:([Trazas].[dbo].[HistoricoDosificaciones].[IX_HistoricoDosificaciones]
> AS [d]), SEEK:([d].[Diario]='Ago 24 2006 12:00AM' AND
> [d].[NroMezclaDia]7), WHERE:([d].[Extension]='6150' AND
> [d].[CodigoFormula]='412761') ORDERED FORWARD)
> |--Clustered Index
> Scan(OBJECT:([Trazas].[dbo].[Componentes].[PK_Componentes] AS [c]),
> WHERE:([c].[CodigoFormula]='412761' AND [c].[Extension]='6150'))
>
>
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida