Jam*_*mes 3 sql-server-2008 sql-server
我是 CTE 的忠实粉丝。他们是最棒的。你知道,我知道,我们都知道。
今天,如果将 CTE 写入真实表,我的查询速度会提高 1000 倍左右。
查询本身在链接中,但我怀疑它并不重要。为简化起见,我需要一份保险单中所有索赔的清单,其中一项索赔满足特定条件(cat = 1)。
简化版本如下所示:
with cat_claims as (select distinct pol_nbr from claims where cat = 1)
select * from claims c
inner join policies p on p.polnbr = c.polnbr
inner join cat_claims cat on c.pol_nbr= cat.pol_nbr
Run Code Online (Sandbox Code Playgroud)
这是超级骗子慢。如果我重写它看起来像这样:
with cat_claims as (select distinct claim_nbr from claims where cat = 1)
select * into cat_claims
from cat_claims
select * from claims c
inner join policies p on p.polnbr = c.polnbr
inner join cat_claims cat on c.pol_nbr = cat.pol_nbr
drop table cat_claims
Run Code Online (Sandbox Code Playgroud)
它的方式,方式更快。这对我来说很奇怪。
问题为什么将 CTE 写入实际表会提供性能改进?
慢计划:
https://www.brentozar.com/pastetheplan/?id=HkyrpAtH4
快速计划:
即使他们是估计的计划,而不是实际的,所不同的我看起来是从连接表来:
RATING_CONTRIB_LOSS,
RATING_CONTRIB_USR,
cmbgrp,
rating_revision_set,和Rating从参数表CTE。
加入这些表会产生巨大的表线轴(懒惰线轴),在实际计划中可能会更大。
对于嵌套循环运算符顶部的每一行,扫描底部结果集,导致
3361 行 * 第 3359 行table spool--> Nested loops-->Top(1)
和
1541 行 * 3359 在第二个table spool--> Nested loops-->Top(1)
这些表假脱机不存在于临时表查询的两个计划中的任何一个中。
我得到的是,插入到表中的查询部分与CTE. 有一些差异,但我认为减速的主要原因是由于工作台线轴。
差的一个例子是,在全表扫描 RATING_CONTRIB_LOSS在CTE计划改变为扫描与所述临时表中计划的残余谓词。
CTE
临时表
您可能会争辩说,使用临时表的查询的第二部分可能会RATING_CONTRIB_LOSS再次访问该表。我不得不同意,因为它将进行昂贵的密钥查找。
但是,CTE计划中的第二个表假脱机也基于与RATING_CONTRIB_LOSS表的嵌套循环连接,临时表计划中没有,这是一个很大的优势。
结论
我确实相信执行时间的差异来自使用临时表结果的查询,而不会使用昂贵的运算符。更具体地说是表线轴。我需要 100% 确定实际计划。
作为旁注,在许多情况下,将 CTE 重写为临时表或仅拆分查询通常可以提供更好的执行时间。
猜测一个装有苹果和梨的袋子里有多少苹果比猜测一个装有苹果、梨、芒果、橙子、桃子……(是的水果 = 桌子)的袋子里有多少苹果更容易。
我还会使用实际的 #temp 表来存储您的中间结果。
使用 CTE 第 1 部分进行计划
RATING_CONTRIB_LOSS & Hash match join <> Nested Loops Join 的区别。休息非常相似,评级表上的相同操作(2x)
| 归档时间: |
|
| 查看次数: |
580 次 |
| 最近记录: |