27

私が解決しようとしている問題は次のとおりです。最近、複数のシャード間でデータベースの負荷を分散できるようにするデータ層の再設計を完了しました。シャードのバランスを保つために、あるシャードから別のシャードにデータを移行できる必要があります。これには、シャード A からシャード B にコピーし、シャード A からレコードを削除することが含まれます。しかし、非常に大きなテーブルがいくつかあり、多くの外部キーがそれらを指しているため、テーブルから 1 つのレコードを削除するのに 1 秒以上かかる場合があります。

場合によっては、テーブルから何百万ものレコードを削除する必要がありますが、実際には時間がかかりすぎます。

外部キーを無効にすることはオプションではありません。行の大量のバッチを削除することもオプションではありません。これは本番アプリケーションであり、大量の削除を行うとリソースがロックされすぎて障害が発生するためです。私は Sql Server を使用しており、パーティション分割されたテーブルについては知っていますが、パーティション分割の制限 (およびエンタープライズ エディションのライセンス料金) は非常に非現実的であり、実行できません。

この問題に取り組み始めたとき、途中で外部キー制約に違反しないように、リーフ レベルからデータ モデルの最上部までの行を削除する方法を理解するアルゴリズムを作成するのが難しいと思いました。しかし、一晩で消える必要があるレコードを削除するには数週間かかるため、その問題を解決しても役に立ちませんでした。

データを仮想的に削除されたものとしてマークする方法を既に構築しているため、アプリケーションに関する限り、データは失われていますが、大きなデータ ファイル、大きなバックアップ、低速のクエリをまだ処理しています。テーブル。

何か案は?ここで関連する古い投稿を既に読んでいますが、役立つものは何も見つかりませんでした。

4

8 に答える 8

31

参照してください: SQL Server での削除の最適化

次の MS サポート記事が参考になるかもしれません: SQL Server のロック エスカレーションによって引き起こされるブロッキングの問題を解決する方法:

大規模なバッチ操作をいくつかの小さな操作に分割します。たとえば、次のクエリを実行して監査テーブルから数十万の古いレコードを削除したところ、他のユーザーをブロックするロック エスカレーションが発生したことが判明したとします。

DELETE FROM LogMessages WHERE LogDate < '2/1/2002'    

これらのレコードを一度に数百ずつ削除することで、トランザクションごとに蓄積されるロックの数を大幅に減らし、ロックのエスカレーションを防ぐことができます。例えば:

SET ROWCOUNT 500
delete_more:
     DELETE FROM LogMessages WHERE LogDate < '2/1/2002'
IF @@ROWCOUNT > 0 GOTO delete_more
SET ROWCOUNT 0

クエリをできるだけ効率的にすることで、クエリのロック フットプリントを減らします。大規模なスキャンまたは多数のブックマーク ルックアップは、ロック エスカレーションの可能性を高める可能性があります。さらに、デッドロックの可能性が高くなり、一般に同時実行性とパフォーマンスに悪影響を及ぼします。

于 2009-07-21T12:35:57.923 に答える
2

新しいファイルを作成し、「削除された」行を除くすべてをコピーしてから、テーブルの名前を交換できます。最後に、古いテーブルを削除します。レコードの大部分を削除している場合、これは実際には高速になる可能性があります。

于 2009-07-21T12:35:27.407 に答える
1

もう 1 つの提案は、テーブルの名前を変更し、ステータス列を追加することです。status = 1 (削除済み) の場合は、表示したくありません。次に、元のテーブルと同じ名前のビューを作成します。このビューは、ステータスが null または = 0 のときにテーブルから選択します (実装方法によって異なります)。削除はユーザーにすぐに表示され、バックグラウンド ジョブが 15 分ごとに実行され、データベース管理者以外は認識されずに実行されるレコードを削除します。

于 2013-07-31T15:49:48.930 に答える
0

SQL 2005または2008を使用している場合は、「スナップショットアイソレーション」を使用すると役立つ可能性があります。これにより、基になるデータ更新操作処理が行われている間、データをユーザーに表示したままにして、コミットされるとすぐにデータを公開できます。削除の実行に30分かかる場合でも、この間、アプリケーションはオンラインのままになります。

スナップショットロックの簡単な入門書は次のとおりです。

http://www.mssqltips.com/tip.asp?tip=1081

削除をできるだけ速くするために削除を高速化する必要がありますが、これにより負担が軽減される場合があります。

于 2009-07-24T04:29:54.390 に答える
0

次のような while ループを使用して、小さなバッチを削除できます。

DELETE TOP (10000) FROM LogMessages WHERE LogDate < '2/1/2002'
WHILE @@ROWCOUNT > 0
BEGIN
    DELETE TOP (10000) FROM LogMessages WHERE LogDate < '2/1/2002'
END
于 2016-12-27T16:06:21.117 に答える
-1

ここにあなたの問題の解決策があります。

DECLARE @RC AS INT
SET @RC = -1

WHILE @RC <> 0
BEGIN
    DELETE TOP(1000000) FROM [Archive_CBO_ODS].[CBO].[AckItem] WHERE [AckItemId] >= 300
    SET @RC = @@ROWCOUNT
    --SET @RC = 0
END
于 2016-12-08T18:36:38.507 に答える