我已经编写了一个小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
答案 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计划将提供明确的答案。