完了までに1時間近くかかる以下のストアドプロシージャがあります。結果セットは約200Kのマシンです。
私がしているのは、リンクサーバーからIDのセットを抽出し、ローカルサーバーでそれらのIDを削除してから、リモートサーバーからそれらのIDのすべての詳細を抽出して挿入することだけです。 INSERTは90%、DELETEテーブルは9%、SELECT INTOは1%です。
idは主キー/クラスター化インデックスです。
DECLARE @ProcessDate DATETIME
SET @ProcessDate = CONVERT(VARCHAR(10), DATEADD(DAY, -3,
GETDATE()), 111)
SELECT DISTINCT id
INTO #temp_machines
FROM remote_server.db.dbo.table1
WHERE dt_modify >= @ProcessDate
DELETE FROM local_server.db.dbo.table2
WHERE id IN ( SELECT id FROM #temp_machines )
INSERT INTO local_server.db.dbo.table2
SELECT *
FROM remote_server.db.dbo.table1
WHERE id IN ( SELECT id FROM #temp_machines )
パフォーマンスの向上に関する提案はありますか?
最初のステップ:調整するものがあり、クエリが単にブロックされていないことを確認します。 sp_WhoIsActive または sp_BlitzFirst (免責事項、私はFirst Responder Kitの寄稿者です)などの無料のツールを使用してこれを行うことができます。
2番目のステップ:ローカル変数 は使用しないでください。
3番目のステップ:多分 一時テーブルのインデックス作成 が役立ちます。
4番目のステップ:待機統計を確認 sp_BlitzFirstを使用してください(私がそれに貢献していることに関する同じ免責事項、何とか何とか何とか)。書かれているクエリは問題ないかもしれませんが、tempdbの競合など、他の問題が発生しています。
「リモートサーバー」とはリンクサーバー(または、少なくとも類似のもの)を意味すると仮定すると、1つの潜在的な問題は、同じデータに相当するものに対して2つのクエリを実行することです。また、IN (SELECT ...)
を使用することにより、サーバーにそのSELECT
ステートメントを行ごとに1回再実行させることができます。
私は次のようなことを試します:
DECLARE @ProcessDate DATETIME
SET @ProcessDate = CONVERT(VARCHAR(10), DATEADD(DAY, -3,
GETDATE()), 111)
SELECT *
INTO #temp_machines
FROM table1
WHERE dt_modify >= @ProcessDate
DELETE t2
FROM table2 t2
INNER JOIN (SELECT DISTINCT id FROM #temp_machines) tm ON (t2.id = tm.id)
INSERT INTO table2
SELECT *
FROM #temp_machines
結局のところ、ある時点でtable1
からすべての一致するデータをローカルDBにプルすることになります。事前に取得しておくと、残りのクエリでリモートサーバーを無視できます。
さらに良いことに、table1.id
が一意または主キーである場合、DELETE
は次のようになります。
DELETE t2
FROM table2 t2
INNER JOIN #temp_machines tm ON (t2.id = tm.id)
table1
に特定のid値のインスタンスが複数ある場合でも、これが機能する可能性があります。
クエリ構文(匿名化、ナッチ)には表示されませんが、あなたの質問はtable1
はリモートサーバー上にあります。おそらく、4部構成の構文を使用して実際に対処しているのでしょう。
[RemoteServerAlias].[DatabaseName].[SchemaName].[TableName]
そのリモートテーブルを更新するとき、SQLには問題を最適化しようとする興味深い時間があります。必要な情報がすべて含まれていないため、非常に疑問のある決定を下すことがあります。そこにある最後のクエリは、リモートテーブルのコンテンツ全体をフィルターする前に、そのサーバーからリモートテーブルの内容全体を確実に取得しています。
最初のクエリが十分に速い場合、つまりSQLがその日付基準を適用している場合は、回避策を提案します。最後にその基準を追加します。
INSERT INTO table2
SELECT *
FROM table1
WHERE id IN ( SELECT id FROM #temp_machines )
AND dt_modify >= @ProcessDate