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

#1 Eladio Rincón
25/08/2006 - 12:33 | Informe spam
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
#2 Alvaro Mosquera
25/08/2006 - 12:51 | Informe spam
Muchas gracias Eladio

"Eladio Rincón" escribió:

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
#3 Alejandro Mesa
25/08/2006 - 14:27 | Informe spam
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'))


Respuesta Responder a este mensaje
#4 Alejandro Mesa
25/08/2006 - 15:04 | Informe spam
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
#5 Eladio Rincón
25/08/2006 - 20:05 | Informe spam
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
Ads by Google
Help Hacer una preguntaSiguiente Respuesta Tengo una respuesta
Search Busqueda sugerida