SQL Serverの世界には、 DROP TABLE
の両方が存在するという神話が根強く残っています。 およびTRUNCATETABLE
コマンドはログに記録されません。
そうではありません。どちらも完全にログに記録されていますが、効率的にログに記録されています。
これは簡単に証明できます。次のコードを実行してテストデータベースとテーブルを設定し、テーブルに10,000行あることを示します。
CREATE DATABASE [TruncateTest]; GO ALTER DATABASE [TruncateTest] SET RECOVERY SIMPLE; GO USE [TruncateTest]; GO CREATE TABLE [TestTable] ( [c1] INT IDENTITY, [c2] CHAR (8000) DEFAULT 'a'); GO SET NOCOUNT ON; GO INSERT INTO [TestTable] DEFAULT VALUES; GO 10000 SELECT COUNT (*) AS N'RowCount' FROM [TestTable]; GO
結果:
RowCount———–
10000
次に、トランザクション内のテーブルを切り捨てて行数をチェックする次のコード:
BEGIN TRAN; GO TRUNCATE TABLE [TestTable]; GO SELECT COUNT (*) AS N'RowCount' FROM [TestTable]; GO
結果:
RowCount———–
0
これでテーブルは空になります。ただし、トランザクションをロールバックして、すべてのデータを元に戻すことはできます:
ROLLBACK TRAN; GO SELECT COUNT (*) AS N'RowCount' FROM [TestTable]; GO
結果:
RowCount———–
10000
明らかにTRUNCATE
操作をログに記録する必要があります。そうしないと、ロールバック操作が機能しません。
では、誤解はどこから来るのでしょうか?
これは、 DROP
の動作に由来します およびTRUNCATE
大きなテーブルでの操作。それらはほぼ瞬時に完了します。fn_dblog
を使用してトランザクションログを確認すると その直後に、操作から生成された少数のログレコードのみが表示されます。この小さな数値は、切り捨てられたり削除されたりするテーブルのサイズとは相関関係がないため、 DROP
のように見えます。 およびTRUNCATE
操作はログに記録されません。
ただし、上記で示したように、完全にログに記録されます。では、操作のログレコードはどこにありますか?
答えは、SQL Server2000SP3で追加された「遅延ドロップ」と呼ばれるメカニズムによってログレコードがすぐに作成されるのではないということです。
テーブルが削除または切り捨てられた場合、テーブルに割り当てられたすべてのデータファイルページの割り当てを解除する必要があります。 SQL Server2000SP3以前のこのメカニズムは次のとおりです。
テーブルに割り当てられたエクステントごとに開始
エクステントの排他的割り当てロックを取得します
プローブしますエクステント内の各ページのページロック(排他モードでロックを取得し、すぐにドロップして、他の人がページをロックしていないことを確認します)
しないでくださいエクステントロックを解除して、他の誰もそのエクステントを使用できないようにします
次のエクステントに移動します
終了
すべてのエクステントロックは操作が終了するまで保持され、各ロックは少量のメモリを使用するため、 DROP
のときにロックマネージャがメモリを使い果たす可能性がありました。 またはTRUNCATE
非常に大きなテーブルが発生しました。一部のSQLServerのお客様は、テーブルが非常に大きくなり、システムメモリの増加を大幅に上回ったため、SQLServer2000でメモリ不足の状態に遭遇し始めました。
遅延ドロップメカニズムは、 DROP
をシミュレートします またはTRUNCATE
テーブルの割り当てを解除して「遅延ドロップキュー」に配置し、後でバックグラウンドタスクで処理できるようにすることで、操作がすぐに完了します。このフック解除および転送操作では、ほんの一握りのログレコードしか生成されません。これは、上記のコード例で実行およびロールバックされている操作です。
「遅延ドロップバックグラウンドタスク」は数秒ごとに起動し、遅延ドロップキューのすべてのページとエクステントの割り当てを解除します。バッチ。操作でメモリが不足しないことを保証します。これらの割り当て解除はすべて完全にログに記録されますが、データまたはインデックスレコードでいっぱいのページの割り当てを解除しても、それらのレコードの個々の削除はログに記録されないことに注意してください。代わりに、ページ全体が、関連するPFS(ページ空き領域)割り当てバイトマップで割り当て解除としてマークされます。
SQL Server 2000 SP3以降、 DROP
を実行すると またはTRUNCATE
テーブルの場合、生成されているログレコードはごくわずかです。 1分ほど待ってから、トランザクションログをもう一度見ると、遅延ドロップ操作によって何千ものログレコードが生成され、それぞれがページまたはエクステントの割り当てを解除していることがわかります。操作は完全かつ効率的にログに記録されます。
上記で作成したシナリオを使用した例を次に示します。
CHECKPOINT; GO TRUNCATE TABLE [TestTable]; GO SELECT COUNT (*) AS N'LogRecCount' FROM fn_dblog (NULL, NULL); GO
結果:
LogRecCount———–
25
ご覧のとおり、10,000ページと1,250エクステントの割り当てを解除したログレコードがTestTableテーブルにないことは明らかです。
数秒待ってから、 fn_dblog
を実行すると もう一度コードを書くと、次のようになります:
———–
3811
割り当てが解除されているページごとに1つずつ、少なくとも10,000のログレコードがないのはなぜか疑問に思われるかもしれません。これは、ページの割り当て解除が効率的にログに記録されるためです。PFSページでの割り当てステータスの変更を反映するデータファイルページごとに1つのログレコードではなく、8つの連続するデータファイルページのPFSページ割り当ての変更を反映する1つのログレコードがあります。
SQL Serverは、現在の回復モデルに基づく完全または最小限のログ記録に関するルールを順守しながら、常に可能な限り少ないトランザクションログを生成しようとします。 unhook-and-transferおよびdeferred-dropメカニズムによって生成された実際のログレコードを確認する場合は、上記のfn_dblogコードのCOUNT(*)を*に置き換え、トランザクション名が DeferredAllocUnitDrop ::Process
。
今後の投稿では、SQLServerストレージエンジンのパフォーマンスの側面に関する他の永続的な神話を支える内部について説明します。