私のプロジェクトでは、以下の T-SQL コードで課題に遭遇しました。
- step1 は、UserModules テーブルに親モジュールとそのサブスクライブしているユーザーを入力します。
- step2 は、Modules_Hierarchy テーブルで step1 のモジュールに関連付けられた子モジュールをチェックし、子モジュールを親モジュールのサブスクライブ ユーザーにマッピングすることによって、UserModules テーブルに有効なレコードを挿入します。このステップは、すべての子モジュールが見つかるまで再帰的に繰り返されます。
問題:
ステップ 2 では、WHILE ループと SELECT ステートメントが相関サブクエリを使用し、テーブル UserModules が INSERT 句と関連する SELECT 句の両方の一部であるため、パフォーマンスが低下し、LOCK エスカレーションの問題でクエリが失敗することがよくあります。
ModulesUsers テーブルの最終的なデータ サイズは 4,200 万で、今後さらに大きくなることが予想されます。
エラー メッセージ:「SQL Server データベース エンジンのインスタンスは、現在 LOCK リソースを取得できません。アクティブなユーザーが少なくなったら、ステートメントを再実行してください。データベース管理者に依頼して、このインスタンスのロックとメモリの構成を確認するか、実行時間の長いトランザクションを確認してください。」</p>
このクエリを最適化する方法、つまり問題を解決するためのステップ 2 を教えてください。
ステップ1:
INSERT INTO UserModules(ModuleID, UserID)
SELECT ModuleID, UserID
FROM TABLEA a
INNER JOIN TABLEB b ON a.ID = b.ID
ステップ2:
DECLARE @cnt int
SET @cnt = 1
WHILE( @cnt > 0 )
BEGIN
SET @cnt = (SELECT COUNT(DISTINCT s.moduleid)
FROM Modules_Hirarchy s WITH (nolock), Modules t
WHERE s.ParentModuleId = t.ModuleId
------------
AND NOT EXISTS
(SELECT ModuleId + EndUserId
FROM UserModules r
WHERE s.moduleid = r.moduleid
AND t.EndUserId = r.EndUserId)
AND s.moduleid + t.EndUserId NOT IN
(SELECT CAST(ModuleId AS varchar) + EndUserId
FROM UserModules ))
IF @cnt = 0
BREAK
INSERT INTO UserModules (ModuleId, EndUserId)
SELECT DISTINCT s.moduleid, t.EndUserId
FROM Modules_Hirarchy s WITH (nolock), UserModules t
WHERE s.ParentModuleId = t.ModuleId
AND NOT EXISTS
(SELECT ModuleId + EndUserId
FROM UserModules r
WHERE s.moduleid = r.moduleid
AND t.EndUserId = r.EndUserId)
END