[英]Joining Onto CTE Performance
我有一个存储过程,在其中使用“公用表表达式”在菜单上建立层次结构路径(因此它可以显示类似“父菜单”->“子菜单”->“子子菜单”->“ ...”)
它非常适合我要使用的功能,当将我从递归CTE获得的信息放入我真正想要的信息时,问题就来了。 我进行从数据到CTE的内部联接,并找到了层次结构路径。 对于返回约300行的存储过程,存储过程平均需要15-20秒。
当我将CTE的结果插入到临时表中并基于该表进行连接时,该过程只需不到一秒钟的时间。
我只是想知道为什么仅使用CTE会花这么长时间,或者我是否在某种程度上滥用了CTE。
**编辑这本质上是存储过程
With Hierarchical_Path (Menu_ID, Parent_ID, Path)
As
(
Select
EM.Menu_Id, Parent_ID,
Convert(varchar(max),
EM.Description) as Path
From
Menu EM
Where
--EM.Topic_No is null
EM.Parent_ID = 0 and EM.Disabled = 0
Union All
Select
EM.Menu_ID,
EM.Parent_ID,
Convert(Varchar(max),E.Path + ' -> ' + EM.Description) as Path
From
Menu EM
Inner Join
Hierarchical_Path E
On
EM.Parent_ID = E.Menu_ID
)
SELECT distinct
EM.Description
,EMS.Path
FROM
dbo.Menu em
INNER JOIN
Hierarchical_Path EMS
ON
EMS.Menu_ID = em.Menu_Id
2 more INNER JOINs
2 Left Joins
WHERE Clause
当我像这样运行查询(加入CTE)时,性能约为20秒。
当我将CTE结果插入到临时表中并加入该表时,性能是瞬时的。
让我的查询更详细一点,似乎它挂在了where子句上。 我想我的问题还不止于CTE何时确切运行以及是否存储在内存中? 我在假设它被调用一次然后在内存中停留的假设下运行,但是在某些情况下它可以被称为多次吗?
区别在于CTE不持久化,而临时表持久化(至少对于会话而言)。 在非持久列上联接意味着SQL与临时表中已预先评估的同一列相比,根本没有数据统计信息。 基本上,临时表会缓存您将使用的内容,而SQL Server可以更好地对其进行优化。 在对函数或表变量的结果进行联接时,也会遇到相同的问题。
我的猜测是,您的CTE执行计划是使用单个线程执行,而您的临时表可以使用多个线程。 您可以通过在运行查询时包括实际的执行计划并在每个运算符上查找两个指向相反方向的水平箭头来检查此情况。 这表明并行性。
PS-尝试设置“设置统计信息打开”和“设置统计信息打开”,以查看运行查询的实际成本是否相同,而与运行时间无关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.