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 の一貫したビューが 1 つしかないことを示唆しています。どんな違いも、そうではないことを証明しています。SQL Server 2008 R2 で実行すると、違いが見つかりました。

結果

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

もちろん、ここではインライン関数が原因である可能性があります。それは確かに私の実行計画を変えました。これは私に教訓を教えてくれました。実行計画をもっとよく理解する必要があります。OPの計画を読むと、決定的な答えが得られると確信しています。

于 2016-02-04T12:57:34.237 に答える