11

私は数百万のレコード(たとえば5000万)に成長できるテーブルを持っています。20分ごとに、20分より古いレコードが削除されます。

問題は、テーブルに非常に多くのレコードがある場合、そのような削除には多くの時間がかかる可能性があり、私はそれをより速くしたいということです。

20分以上経過したレコードのみを削除したいので、「テーブルの切り捨て」を実行できません。「削除」を行って削除する必要のある情報をフィルタリングする場合、サーバーがログファイルなどを作成していると思いますが、これには時間がかかりますか?

私は正しいですか?削除を最適化するためにフラグまたはオプションを停止してから、停止したオプションをオンにする方法はありますか?

4

4 に答える 4

15

バッチ削除の提案を拡張するには、これをはるかに定期的に(おそらく20秒ごとに)行うことをお勧めします-バッチ削除は簡単です:

WHILE 1 = 1 
    BEGIN 
        DELETE TOP ( 4000 )
        FROM    YOURTABLE
        WHERE   YourIndexedDateColumn < DATEADD(MINUTE, -20, GETDATE()) 
        IF @@ROWCOUNT = 0 
            BREAK    
    END

ロックが解除されるのを待つ間、挿入はわずかに遅れる場合がありますが、エラーではなく挿入する必要があります。

ただし、テーブルに関しては、非常に高速なRAID 10アレイ(おそらくパーティション化されている場合もあります)で見られると予想されるトラフィックがこれだけ多いテーブルは、ディスクに対応していますか?トランザクションログはデータファイルとは異なるディスクにありますか?- 彼らはする必要があります

編集1-あなたのコメントへの応答

データベースをSIMPLEリカバリにするには:

ALTER DATABASE Database Name SET RECOVERY='SIMPLE'

これにより、基本的に、特定のデータベースでのトランザクションログがオフになります。つまり、データが失われた場合は、最後の完全バックアップ以降のすべてのデータを失う必要があります。それでよければ、大規模なトランザクションを実行するときに多くの時間を節約できるはずです。(トランザクションが実行されている間、ロギングは引き続きSIMPLEで行われることに注意してください-トランザクションのロールバックを有効にします)。

データベース内にデータを失う余裕がないテーブルがある場合は、データベースを完全リカバリモードのままにする必要があります(つまり、トランザクションはログに記録されます(サーバーのメンテナンスプランによって* .trnファイルにフラッシュされることが望ましい)。私の質問で述べたように、2つのデータベース(1つはFULL、もう1つはSIMPLE)があることを妨げるものは何もありません。FULLデータベースは、データを失う余裕がないフォアテーブルになります(つまり、トランザクションログを適用してデータを復元することができます)特定の時間)およびSIMPLEデータベースは、障害が発生した場合にデータの損失を許容できるこれらの大規模なトラフィックの多いテーブル用です。

これはすべて、毎晩完全な(* .bak)ファイルを作成し、30分ごとにログファイルを* .trnファイルにフラッシュすることを前提としています)。

インデックスの質問に関しては、実行プランを確認して「テーブルスキャン」が表示された場合、日付列にインデックスを付けることが不可欠です。これは、インデックスが欠落していることを示します。

私が推測するあなたの日付列は、DEFAULTをgetdate()に設定する制約のあるDATETIMEですか?

これをBIGINTYYYYMMDDHHMMSSに置き換えてから、その列にCLUSTEREDインデックスを適用すると、パフォーマンスが向上する場合があります。ただし、テーブルごとに1つのクラスター化インデックスしか持てないことに注意してください。非クラスター化インデックスを使用します。(知らなかった場合、クラスター化インデックスは基本的にSQLに情報をこの順序で格納するように指示します。つまり、20分を超える行を削除すると、SQLはページ間を移動するのではなく、文字通り順番に情報を削除できます。

于 2012-09-10T14:00:35.870 に答える
10

ログの問題は、トランザクションで削除されたレコードの数が原因である可能性があります。さらに悪いことに、エンジンがレコードごとにロックを要求している可能性があります(またはページごとにそれほど悪くはありません)

ここで重要なことの1つは、削除するレコードを決定する方法です。日時フィールドを使用することを前提としています。その場合は、列にインデックスがあることを確認してください。そうでない場合は、テーブルの順次スキャンがプロセスに実際にペナルティを課します。 。

ユーザーの同時実行性と削除の時間に応じて、2つのことを実行できます。

  1. 削除時に誰も読み取りまたは書き込みを行わないことを保証できる場合は、テーブルを排他モードでロックして削除し(これにより、エンジンから1つのロックのみが取得されます)、ロックを解除できます。
  2. バッチ削除を使用できます。削除する行を提供するカーソルを使用してスクリプトを作成し、トランザクションを開始してすべてのXレコード(理想的には5000)をコミットするため、トランザクションを短くし、それほど多くのロックを取得しないようにすることができます。

削除プロセスのクエリプランを見て、それが何を示しているかを確認してください。大きなテーブルのシーケンシャルスキャンは決して良いことではありません。

于 2012-09-10T13:15:32.333 に答える
1

残念ながら、この質問の目的のために、そして幸いなことにSQLサーバー内のデータベースの一貫性と回復可能性のために、データベースを単純回復モードにしても、ログは無効になりません。すべてのトランザクションは、データファイルにコミットする前にログに記録されます。唯一の違いは、トランザクションがロールバックされるか、シンプルリカバリモードでコミットされた直後に、ログのスペースが解放されることです(ほとんどの場合)。 、ただし、これはDELETEステートメントのパフォーマンスに何らかの影響を与えることはありません。

于 2014-02-19T18:57:29.427 に答える
0

3つのインデックスと多くの外部キーを持つ大きなテーブルから行の70%以上を削除する必要がある場合にも、同様の問題が発生しました。

このシナリオでは、必要な行を一時テーブルに保存し、元のテーブルを切り捨てて、次のように行を再挿入しました。

SELECT * INTO #tempuser FROM [User] WHERE [Status] >= 600;
TRUNCATE TABLE [User];
INSERT [User] SELECT * FROM #tempuser;

私はこのテクニックを次の説明のリンクで学びました:

DELETEは完全にログに記録された操作であり、問​​題が発生した場合にロールバックできます

TRUNCATE個々の行の削除をログに記録せずに、テーブルからすべての行を削除します

この記事では、多くのレコードを削除する際の遅延を解決するための他の戦略を探ることができます。

于 2017-06-27T21:03:40.590 に答える