5

私はこのクエリを持っています:

DELETE from MailingListTable where Md5Hash in (
   SELECT
      dbo.ListItems.Md5Hash
   FROM dbo.Lists
   INNER JOIN dbo.ListItems ON dbo.Lists.Id = dbo.ListItems.ListId
   where dbo.Lists.IsGlobal = 1
 )

MailingListTable は、複数のリストから動的に構築されます。次に、上記のクエリを実行して、グローバル削除リストにあるすべてのリスト アイテムを削除します。

小規模なセットでは問題ありませんが、大規模なセットでは 5 ~ 8 分ほどかかることがあります (私が行ったいくつかのテストに基づく)。もっといい書き方がないか気になります。削除ステートメントで結合を使用できるとは思いません。そのため、サブクエリを選択しました。

も使用してみEXISTSましたが、はるかに遅くなりました。common-table expressionsSQL Server 2008 を使用しているため、使用した方がよいでしょうか?

4

1 に答える 1

8

(a) 何百万もの行を削除しており、(b) ログを回転ドアのように扱っているため、長い時間がかかると思います。IN の代わりに EXISTS を使用するか、サブクエリを CTE に変更するか、JOIN を使用するため、魔法のように 5 ~ 8 分から 5 秒になることはありません。先に進んで試してみてください。

DELETE ml 
  FROM dbo.MailingListTable AS ml
  INNER JOIN dbo.ListItems AS li
  ON ml.Md4Hash = li.Md5Hash
  INNER JOIN dbo.Lists AS l
  ON l.Id = li.ListId 
  WHERE l.IsGlobal = 1;

DELETE問題は、削除する行を識別するために使用される方法ではなく、実行に関連する I/O にあることはほぼ確実です。まったくSELECT同じデータを使用し、インデックス構造などを変更せずに、分離レベルに関係なく、5〜8分かからないに違いありません。

それで、どのように修正するのですか?

まず、ログがそのサイズのトランザクションを処理するように調整されていることを確認してください。

  • このような操作中にログが大きくなる必要がないように、ログのサイズをあらかじめ決めておいてください。正確な理想的なサイズは、Stack Overflow の誰かが教えてくれるものではありません。

  • 自動拡張が 10% や 1MB などのばかげたデフォルトに設定されていないことを確認してください。Autogrow はフォールバックである必要がありますが、必要な場合は、特定のアクティビティをカバーするために複数回ではなく、1 回だけ実行する必要があります。そのため、固定サイズ (サイズ + 期間を予測可能にする) であることと、サイズが妥当であること (一度だけ発生するようにすること) を確認してください。何が合理的ですか?わかりません - 「場合による」が多すぎます。

  • ログを圧縮するすべてのジョブを無効にします - 永久に。ログファイルを繰り返し圧縮してログの増大を「防ぐ」のではなく、ケースバイケースで制御不能なログに対処します。

次に、これらの削除をチャンクにバッチ処理するようにクエリを変更することを検討してください。どのような種類のトランザクション期間につながる行数に基づいて、TOP (?)パラメーターをいじることができます (より多くの情報があったとしても、これに関する魔法の公式はありません)。

CREATE TABLE #x
(
  Md5Hash SOME_DATA_TYPE_I_DO_NOT_KNOW PRIMARY KEY
);

INSERT #x SELECT DISTINCT li.Md5Hash
  FROM dbo.ListItems AS li
  INNER JOIN dbo.Lists AS l
  ON l.Id = li.ListId 
  WHERE l.IsGlobal = 1;

DECLARE @p TABLE(p INT SOME_DATA_TYPE_I_DO_NOT_KNOW PRIMARY KEY);

SELECT @rc = 1;

WHILE @rc > 0
BEGIN
  DELETE @p;

  DELETE TOP (?)  
    OUTPUT deleted.Md5Hash INTO @p
    FROM #x;

  SET @rc = @@ROWCOUNT;

  BEGIN TRANSACTION;    

    DELETE ml FROM dbo.MailingListTable AS ml
    WHERE EXISTS (SELECT 1 FROM @p WHERE Md5Hash = ml.Md5Hash);

  COMMIT TRANSACTION;
  -- to minimize log impact you may want to CHECKPOINT
  -- or backup the log here, every loop or every N loops
END

これにより、操作にかかる合計時間が長くなる可能性があります (特に、各ループでバックアップまたはチェックポイントを実行する場合、または を使用して人為的な遅延を追加する場合WAITFOR、またはその両方の場合)、代わりに短いトランザクションを待機して、他のトランザクションがチャンク間に忍び込むことを許可する必要があります。プロセス全体の。また、ログへの個々の影響が少ないため、実際にははるかに速く終了する可能性があります. しかし、問題は 5 ~ 8 分かかることではなく、おそらく 5 ~ 8 分かかっブロックすることだと思います。これにより、それが大幅に軽減されるはずです(そして、そうであれば、なぜ時間がかかるかを気にしますか?).

このテクニックについては、こちらに詳しく書いています

于 2013-09-05T18:03:44.887 に答える