Sql server DMV上的递归公共表表达式是否应该构建在缓存数据上?

Sql server DMV上的递归公共表表达式是否应该构建在缓存数据上?,sql-server,tsql,common-table-expression,dynamic-management-views,Sql Server,Tsql,Common Table Expression,Dynamic Management Views,我已经编写了一个小CTE来获取头部拦截器进程的总阻塞时间,我不确定是否应该首先将我希望CTE运行的所有进程复制到一个临时表中,然后在此表上执行查询-即,我希望确保在查询运行和(最坏情况下)时,数据不能在我脚下更改,我最终得到了一个无限递归循环 这是我的SQL,包括temp表-出于性能原因,我不想使用该表,而是直接转到CTE中的sysprocesss dmv,但我不确定这可能带来的影响 DECLARE @proc TABLE( spid SMALLINT PRIMARY KEY,

我已经编写了一个小CTE来获取头部拦截器进程的总阻塞时间,我不确定是否应该首先将我希望CTE运行的所有进程复制到一个临时表中,然后在此表上执行查询-即,我希望确保在查询运行和(最坏情况下)时,数据不能在我脚下更改,我最终得到了一个无限递归循环

这是我的SQL,包括temp表-出于性能原因,我不想使用该表,而是直接转到CTE中的sysprocesss dmv,但我不确定这可能带来的影响

DECLARE @proc TABLE(
    spid SMALLINT PRIMARY KEY, 
    blocked SMALLINT INDEX blocked_index, 
    waittime BIGINT)

INSERT INTO @proc 
SELECT spid, blocked, waittime 
FROM master..sysprocesses 

;WITH block_cte AS 
(
    SELECT spid, CAST(blocked AS BIGINT) [wait_time], spid [root_spid] 
    FROM @proc
    WHERE blocked = 0
    UNION ALL
    SELECT blocked.spid, blocked.waittime, block_cte.spid 
    FROM @proc AS blocked
    INNER JOIN block_cte ON blocked.blocked = block_cte.spid
)
SELECT root_spid blocking_spid, SUM(wait_time) total_blocking_time
FROM block_cte 
GROUP BY root_spid

这个问题最好转移到堆栈DBA。我相信那些聪明的人不仅能告诉你答案,还能告诉你背后的原因

我自己也不确定,我决定测试一下

我的脚本捕获了1000次的记录计数。现在要做到这一点,我必须绕过CTE的几个限制。在…之间你不能使用。这使得计算记录相当困难。因此,我创建了一个内联表函数来从sysprocesss返回当前行数

系统进程计数功能

CREATE FUNCTION ProcessCount()
RETURNS TABLE 
AS
RETURN 
(
    -- Return the current process count.
    SELECT 
        COUNT(*) AS RecordCount
    FROM
        Master..sysProcesses
)
;
我把这个函数包装在一个CTE中

CTE

WITH RCTE AS 
(
    /* CTE to test if recursion is effected by updates to 
     * underlying data.
     */
        -- Anchor part.
        SELECT 
            1 AS ExecutionCount,
            1 AS JoinField,
            RecordCount
        FROM
            ProcessCount()          

    UNION ALL

        -- Recursive part.
        SELECT 
            r.ExecutionCount + 1    AS ExecutionCount,
            1 AS JoinField,
            pc.RecordCount
        FROM
            ProcessCount() AS pc
                INNER JOIN RCTE AS r        ON r.JoinField = 1
        WHERE
            r.ExecutionCount < 1000

)
SELECT 
    MIN(RecordCount)    AS MinRecordCount,
    MAX(RecordCount)    AS MaxRecordCount
FROM 
    RCTE
OPTION 
    (MAXRECURSION 1000)
;
GO

当然,内联函数可能是罪魁祸首。它确实改变了我的执行计划。这给了我一个教训。我真的需要更好地理解执行计划。我相信阅读老年退休金计划会提供一个明确的答案

除非将MAXRECURSION选项设置为0,否则无需担心无限循环。默认递归限制为100。现在我不是100%确定,但我希望它能保护您免受流沙的影响。是的,我不会将MAXRECURSION设置为0:)-但我可能会将其设置为100以上。很高兴知道CTE对DMV的“推荐做法”是什么-我感觉这基本上相当于在DMV上运行一组长的重复查询,而且,由于DMV中的D,如果我想保证一致性,我应该复制到临时表中。谢谢-DBA交换的优点-我已经忘记了这一点。是的,所以你的发现确实指向了整个CTE执行过程中的观点变化——感谢你巩固了这一点!我想我现在还是用我的表变量吧
Run    Min   Max
1      113   254
2      107   108
3      86    108