Met*_*hor 1 performance sql-server t-sql sql-server-2012 gaps-and-islands
下面的查询,对一个大约 600 万行的表运行需要 25 秒。当我删除最终订单时,它会在 3 秒内运行。表上没有索引(它是一个中间 SSIS ETL 目标,后来被拉入 DW。)
它不是缓存。我以任何顺序多次运行它,结果一致。
查询本身会检查序列号中的差距。SSIS 将使用它来查看是否需要重新获取任何内容。
;with edges as
(
select
ROW_NUMBER() over (partition by s1.SiteIDNumber order by s1.SequenceNumber) as rn,
s1.SiteIDNumber,
s1.SequenceNumber
from TestPlay s1
left join TestPlay s2 on s2.SiteIDNumber = s1.SiteIDNumber and s2.SequenceNumber = s1.SequenceNumber + 1
left join TestPlay s3 on s3.SiteIDNumber = s1.SiteIDNumber and s3.SequenceNumber = s1.SequenceNumber - 1
where s2.SiteIDNumber is null
or s3.SiteIDNumber is null
),
gaps as
(
select
e.rn,
e.SiteIDNumber,
e.SequenceNumber + 1 as StartSeq,
e2.SequenceNumber - 1 as EndSeq
from edges e
join edges e2 on e2.SiteIDNumber = e.SiteIDNumber and e2.rn = e.rn+1
where e.rn = (e.rn / 2) * 2
)
select * from gaps order by rn
Run Code Online (Sandbox Code Playgroud)
这是执行计划中唯一似乎不同的部分:
使用 ORDER BY(25 秒):

无订单(3秒):

合并连接就像一个拉链——如果你不关心顺序,SQL Server 知道它可以按照它想要的任何方式对输入进行排序,而不必担心重新排序任何东西。当您添加 order by 时,在这种情况下合并连接不再是最佳选择,因为按照表达式定义的顺序对第一个 CTE 进行两次物化和排序显然必须比看起来更昂贵。ROW_NUMBER()
一种解决方法,在周五的啤酒时间想一下袖口:
;WITH ...
(
)
SELECT * INTO #x FROM gaps;
SELECT * FROM #x ORDER BY rn;
Run Code Online (Sandbox Code Playgroud)
但是,我敢打赌,如果您四处寻找一个名叫 Itzik Ben-Gan 的人,您会发现更有效的方法来解决涉及间隙和岛屿的问题(或者建议不要尝试以您正在排序的方式进行排序)。