No exemplo abaixo o resultado de Index Spool
já está ordenado, por que temos Top N Sort
aqui ao invés de simples Top
?
use tempdb;
go
create table dbo.t1 (id int identity primary key, v int);
create table dbo.t2 (id int identity primary key, v int);
insert into dbo.t1
(v)
select top (1000)
row_number() over (order by 1/0)
from
master.dbo.spt_values a cross join
master.dbo.spt_values b;
insert into dbo.t2
(v)
select top (10000)
row_number() over (order by 1/0) + 10000
from
master.dbo.spt_values a cross join
master.dbo.spt_values b;
set statistics xml, io on;
select
sum(a.v + b.v)
from
dbo.t1 a outer apply
(select top (1) v from dbo.t2 where v >= a.v order by v) b;
set statistics xml,io off;
go
drop table dbo.t1, dbo.t2;
go
É reproduzível em todas as versões a partir de 2008 R2
(só não tenho servidor com versões anteriores para testar)
É uma limitação um tanto irritante do otimizador atual.
Eu escrevi sobre isso um pouco como parte de The Eager Index Spool e The Optimizer :
Porque você faz o pedido por
[v]
, enquanto sua chave primária está ativada[id]
.BTW: a consulta pode se tornar um pouco mais rápida, quando você usa
SUM(a.v) + ISNULL(SUM(b.v), NULL)
em vez desum(a.v + b.v)
.Por outro lado, o resultado pode variar um pouco neste caso, já que você usa OUTER APPLY (semelhante a um LEFT JOIN), então quando não houver nenhum registro encontrado para a "table"
[b]
, ele também ignoraria oa.v
na consulta original (já quea.v + NULL
éNULL
) enquantoa.v
estaria na soma total da minha versão sugerida (são seus dados, então você tem que decidir, se permanecer nosum(a.v + b.v)
seria um bom alvo para um comentário dizendo, que este é o comportamento pretendido : -).