是否应该在缓存数据上构建dmvs上的递归公用表表达式?

时间:2016-02-04 11:02:28

标签: sql-server tsql common-table-expression dynamic-management-views

我已经编写了一个小CTE来获取磁头阻塞程序的总阻塞时间,我不确定是否应该首先将我希望CTE运行的所有进程复制到临时表中然后执行对此进行查询 - 即我想确保在查询运行时数据不会在我的脚下发生变化(最糟糕的情况),我最终得到一个无限递归循环!

这是我的SQL,包括临时表 - 由于性能原因,我不想使用该表,而是直接转到我的CTE中的sysprocesses 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

1 个答案:

答案 0 :(得分:1)

这个问题可能最好转移到Stack DBA。我相信那些聪明的家伙和女孩不仅可以告诉你答案,还可以告诉你背后的原因。

不确定自己我决定测试它......

我的脚本从sysProcesses 1000次捕获记录数。现在要做到这一点,我不得不绕过CTE的几个限制。在other restrictions中;你不能使用aggregate functions。这使计数记录变得非常困难。所以我创建了一个内联表函数来从sysProcesses返回当前行数。

sysProcess计数功能

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

如果最小和最大记录计数总是相等,则表明在整个查询中只使用了一个sysProcesses的一致视图。任何差异都证明情况并非如此。在SQL Server 2008 R2上运行我发现了差异:

<强>结果

Run    Min   Max
1      113   254
2      107   108
3      86    108

当然,内联函数可能归咎于此。它确实改变了我的执行计划。这教会了我一课。我真的需要更好地理解执行计划。我确信阅读OPs计划将提供明确的答案。