ゲスト作成者:Derik Hammer(@SQLHammer)
TRUNCATETABLEとDELETEの違いは誤解されることがよくあります。 TRUNCATETABLEはロールバックできないという神話を反証しようとしています:
マニュアルを読む
TRUNCATETABLEに関するBooksOnlineの記事はかなり説明的です:
「個々の行の削除をログに記録せずに、テーブルまたはテーブルの指定されたパーティションからすべての行を削除します。 TRUNCATE TABLEは、WHERE句のないDELETEステートメントに似ています。ただし、TRUNCATE TABLEはより高速で、使用するシステムおよびトランザクションログリソースが少なくなります。」TRUNCATETABLEが使用する少ないという事実 トランザクションログリソースは、ある程度トランザクションログに書き込むことを意味します。どれだけの量を調べて、ロールバックできるかを調べてみましょう。
証明する
以前の投稿で、ポールランダルはこれを細心の注意を払って説明しましたが、この神話の両方の要素を反証するために非常に単純な再現を提供することが有用だと思いました。
TRUNCATE TABLEをロールバックできますか?
TRUNCATETABLEをロールバックできることを証明するのは簡単です。 TRUNCATE TABLEをトランザクションに入れて、ロールバックします。
USE demo; BEGIN TRANSACTION; SELECT COUNT(*) [StartingTableRowCount] FROM [dbo].[Test]; TRUNCATE TABLE [dbo].[Test]; SELECT COUNT(*) [TableRowCountAfterTruncate] FROM [dbo].[Test]; ROLLBACK TRANSACTION; SELECT COUNT(*) [TableRowCountAfterRollback] FROM [dbo].[Test];
テーブルには100,000行あり、ロールバック後に100,000行に戻ります:
TRUNCATE TABLEはログに書き込みますか?
チェックポイントを実行することにより、クリーンな開始点を取得します。次に、TRUNCATETABLEの前後のログレコードを確認できます。
USE demo; CHECKPOINT; SELECT COUNT(*) [StartingLogRowCount] FROM sys.fn_dblog (NULL, NULL); TRUNCATE TABLE [dbo].[Test]; SELECT COUNT(*) [LogRowCountAfterTruncate] FROM sys.fn_dblog (NULL, NULL);
TRUNCATE TABLEコマンドは、237個のログレコードを生成しました(少なくとも最初は)。これにより、ロールバックを実行できるようになり、SQLServerが最初に変更を登録する方法がわかります。
DELETEについてはどうですか?
DELETEとTRUNCATETABLEの両方がログに書き込み、ロールバックできる場合、それらの違いは何ですか?
上記のBOLリファレンスで述べたように、TRUNCATETABLEはより少ないシステムおよびトランザクションログリソースを使用します。 TRUNCATETABLEコマンドに対して237個のログレコードが書き込まれたことはすでに確認しました。それでは、DELETEを見てみましょう。
USE demo; CHECKPOINT; SELECT COUNT(*) [StartingLogRowCount] FROM sys.fn_dblog (NULL, NULL); DELETE FROM [dbo].[Test]; SELECT COUNT(*) [LogRowCountAfterDelete] FROM sys.fn_dblog (NULL, NULL);
DELETE用に440,000を超えるログレコードが書き込まれるため、TRUNCATEコマンドの方が明らかにはるかに効率的です。
まとめ
TRUNCATE TABLEはログに記録されたコマンドであり、ロールバックでき、同等のDELETEよりもパフォーマンスが大幅に向上します。テーブルに存在するよりも少ない行を削除する場合は、DELETEが重要になります(TRUNCATE TABLEはWHERE句を受け入れないため)。 DELETEをより効率的にするためのアイデアについては、AaronBertrandの投稿「大規模な削除操作をチャンクに分割する」を参照してください。