2

我已经写了一点 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
4

1 回答 1

1

这个问题可能最好转给 Stack DBA。相信那些聪明的小伙伴们不仅能告诉你答案,还能告诉你背后的原因。

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

我的脚本从sysProcesses捕获记录计数1,000 次。现在要做到这一点,我必须绕过 CTE 的几个限制。除其他限制外;你不能使用聚合函数。这使得计数记录非常困难。所以我创建了一个内联表函数来从 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 计划会提供明确的答案。

于 2016-02-04T12:57:34.237 回答