すべて(1200万)のレコードを削除した後、SQL Serverの「空のテーブル」は遅いですか?


27

約150列のSQL Server 2008インスタンスがあります。以前、このテーブルに約1200万のエントリを追加しましたが、新しいデータセットに備えてテーブルをクリアしました。

しかし、空のテーブルの上に即座に実行されたかつてのようなことをコマンドcount(*)select top 1000では、SQL Management Studio今、実行に長い年月がかかります。

SELECT COUNT(*) FROM TABLE_NAME 

0を返すのに11分以上かかりSELECT TOP 1000、空のテーブルを返すのに10分近くかかりました。

また、ハードドライブの空き領域が文字通り消えてしまったことにも気付きました(約100Gから20Gに減少)。間に発生した唯一のことは、私が実行した単一のクエリでした:

DELETE FROM TABLE_NAME

世界では何が起こっているのですか?!?


5
データベースで使用している復旧モデルは何ですか?「フル」の場合、SQLインスタンスはそれらのすべての削除の記録を保存します。これは、空き領域が移動した場所です。完全復旧が必要な場合は、のTRUNCATE TABLE代わりに使用することをお勧めしますDELETE FROM
Tullo_x86

2
150列?そのテーブルいっぱいになる可能性があります-ほとんどのタプルははるかに小さいはずです。ただし、完全なコンテキストなしで言うことは不可能です。
時計仕掛けのミューズ

回答:


42

あなたはすでに、なぜTRUNCATEよりもはるかに速く/より良く/よりセクシーになるのかと言われていますがDELETE、まだ対処するための質問が残っています:

完了SELECT後になぜ遅くなるのですか?DELETE

それは、行をゴースト化しDELETEだけだからです。テーブルは、行がなくても、1200万行あるときと同じ大きさです。行(0)をカウントするには、12M行をカウントするのと同じくらい時間がかかります。やがてゴーストクリーンアッププロセスはこれらのゴースト化されたレコードをガベージコレクションし、ゴーストのみを含むページの割り当てを解除し、SELECTを高速化します。しかし、今のところ、perfmon をチェックインすると、おそらくが急上昇しています。テーブルを再構築することで速度を上げることもできます。Skipped Ghosted Records/secSELECT COUNT(*)ALTER TABLE ... REBUILD

TRUNCATE 幽霊を残さないので、この問題も処理していました。

ストレージエンジンの内部:ゴーストクリーンアップの詳細」も参照してください。


13

DELETEステートメントは、テーブルから行を一度に1つずつ削除し、の各行をログに記録し、情報transaction logを維持しlog sequence number (LSN)ます。テーブルには膨大なデータ(1200万レコード)があると述べたので、削除後にハードディスクの空き容量がなくなったら、データベースログファイルのサイズを確認します。おそらく成長したでしょう。

より良い方法は次のとおりです。

TRUNCATE TABLE_NAME

2
+ 1、Oracle DBについてもまったく同じです。レコードをログに記録するステートメントを使用すると、データベースの速度が低下します。
ペトロセメニュク

@PetroSemeniuk私がOracleで思い出したことから、deleteは最高水準点をそのままにして、truncateは最高水準点をリセットします。フルスキャンが必要な操作は、最高水準点までブロックをスキャンすると考えています。したがって、削除はインデックス付きの操作には役立ちますが、スキャンには役立ちません。TRUNCATEは適切な操作でした。
グレン

3

(これはもともと@DaveEの回答に対するコメントでしたが、長くなったため、独自の回答に入れました)

TRUNCATE あるログに記録された操作。それ以外の場合は、ACIDに準拠していない必要があります。しかし、間の違いTRUNCATEDELETE

  • ログ領域の使用:TRUNCATE解放されたページ/エクステントのみを記録しますが、DELETE個々の行を記録します。
  • ロックの使用:行ロックを使用TRUNCATEするのDELETEとは対照的に、テーブルロックとページロックを使用するため、一般的にロックの使用は少なくなります**。
  • IDENTITYシーケンス:TRUNCATEテーブルのIDシーケンスをリセットします(存在する場合)。

(*エクステント= 8ページ。TRUNCATEエクステントがすべて1つのテーブルからの場合はエクステントをログ/削除します。それ以外の場合は、混合エクステントからページをログ/削除します。

**これの1つの副作用はDELETE FROM TABLE、操作が排他的なテーブルロックを取得できるかどうかに応じて、空のページがテーブルに割り当てられたままになる可能性があることです。

だから(元の質問に戻って)、テーブルを空にしているが構造を保持したい場合TRUNCATE TABLEよりも決定的に優れDELETE FROM TABLEています(NB:TRUNCATE別のテーブルの外部キーによって参照されるテーブルでは使用できません)。

@Tulloのコメントに記載されているように、データベースの復旧モデルも確認してください。満杯の場合は、ログのバックアップを開始するか、復旧モデルをシンプルに変更する必要があります。これらのいずれかを実行したら、その空き領域をすべて再利用するために、ログファイルを一度限りの操作(NB:ログファイルのみ)で圧縮することをお勧めします。

最後に、別の注意事項-テーブル統計。UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE`を実行して、クエリオプティマイザーが古い統計によってトリップしないようにします。


2

(注:私はDBAではありません)DELETEはログに記録される操作であり、使用されているスペースを解放しません。おそらく、大きなトランザクションログがスペースを占有し、「空の」テーブルスペースで実行されているテーブルスキャンがあるでしょう。トランザクションログをクリアし、データベースを圧縮する必要があると思います。 このStackOverflowの記事を読んで、始めてください。

将来これを行う場合は、TRUNCATE TABLEを使用します。

編集:TRUNCATEがログに記録されないという私の声明はエラーでした。削除されました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.