Sql 加入CTE性能

Sql 加入CTE性能,sql,sql-server,performance,common-table-expression,Sql,Sql Server,Performance,Common Table Expression,我有一个存储过程,在这个过程中,我使用一个公共表表达式在菜单上构建一个分层路径(这样它可以显示类似于父菜单->子菜单->子子菜单->…) 它对于我想要使用它的目的非常有效,问题是当我将从递归CTE获得的信息放入我真正想要的信息中时。我从我的数据到CTE做一个内部连接,并得到分层路径。对于返回约300行的内容,存储过程平均需要15-20秒 当我将CTE的结果插入临时表并基于该表进行连接时,该过程只需不到一秒钟的时间 我只是想知道为什么只使用CTE需要这么长时间,或者我是否在某种程度上滥用了CTE

我有一个存储过程,在这个过程中,我使用一个公共表表达式在菜单上构建一个分层路径(这样它可以显示类似于父菜单->子菜单->子子菜单->…)

它对于我想要使用它的目的非常有效,问题是当我将从递归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执行计划是使用单个线程执行,而临时表可以使用多个线程。您可以在运行查询时包括实际执行计划,并在每个运算符上查找指向相反方向的两个水平箭头,从而检查这一点。这表明了并行性


注意-尝试设置“set statistics io on”和“set statistics time on”,以查看无论运行持续时间如何,运行查询的实际成本是否相同。

请在此处显示可比较的查询。递归CTE相对较慢,可能涉及多个表扫描。除非您提供有关CTE中所涉及的表的更多详细信息以及这些表中的大致行数,否则我相信无法回答您的问题question@a1ex07你根本不能这么说。非递归CTE相当于视图。它在查询编译期间完全消失。在递归情况下,它完全取决于您正在做什么。如果您发布where子句或其他连接,它可能更有意义。你在CTE里做的一切对我来说都很正常。