このシリーズの最初のパートでは、ロギングに関する基本的な用語を紹介したので、この投稿を続ける前にそれを読むことをお勧めします。このシリーズで取り上げる他のすべてのことは、トランザクションログのアーキテクチャの一部を知っている必要があるため、今回はそれについて説明します。シリーズに従わない場合でも、以下で説明する概念のいくつかは、DBAが本番環境で処理する日常のタスクについて知っておく価値があります。
構造階層
トランザクションログは、下の図1に示すように、3レベルの階層を使用して内部的に編成されています。
図1:トランザクションログの3レベルの構造階層
トランザクションログには、実際のログレコードを格納するログブロックを含む仮想ログファイルが含まれます。
仮想ログファイル
トランザクションログは、仮想ログファイルと呼ばれるセクションに分割されます。 、一般的には単に VLF と呼ばれます 。これは、SQLServerのログマネージャーがトランザクションログでの操作を簡単に管理できるようにするために行われます。データベースが最初に作成されたとき、またはログファイルが自動的に大きくなるときに、SQL Serverによって作成されるVLFの数を指定することはできませんが、影響を与えることはできます。作成されるVLFの数のアルゴリズムは次のとおりです。
- ログファイルのサイズが64MB未満:4つのVLFを作成し、それぞれのサイズは約16MBです
- ログファイルのサイズは64MBから1GB:それぞれが合計サイズの約1/8の8つのVLFを作成します
- 1GBを超えるログファイルサイズ:16個のVLFを作成し、それぞれが合計サイズの約1/16になります
SQL Server 2014より前では、ログファイルが自動拡張されると、ログファイルの最後に追加される新しいVLFの数は、自動拡張サイズに基づいて上記のアルゴリズムによって決定されます。ただし、このアルゴリズムを使用すると、自動拡張サイズが小さく、ログファイルで多数の自動拡張が行われると、非常に多くの小さなVLFが発生する可能性があります(VLFフラグメンテーションと呼ばれます)。 )これは、一部の操作で大きなパフォーマンスの問題になる可能性があります(ここを参照)。
この問題により、SQL Server 2014では、ログファイルの自動拡張のアルゴリズムが変更されました。自動拡張サイズがログファイルの合計サイズの1/8未満の場合、新しいVLFが1つだけ作成されます。それ以外の場合は、古いアルゴリズムが使用されます。これにより、大量の自動拡張が行われたログファイルのVLFの数が大幅に減少します。このブログ投稿で違いの例を説明しました。
各VLFにはシーケンス番号があります これは一意に識別され、さまざまな場所で使用されます。これについては、以下および今後の投稿で説明します。新しいデータベースの場合、シーケンス番号は1から始まると思いますが、そうではありません。
SQL Server 2019インスタンスで、ファイルサイズを指定せずに新しいデータベースを作成し、次のコードを使用してVLFを確認しました。
CREATE DATABASE NewDB; GO SELECT [file_id], [vlf_begin_offset], [vlf_size_mb], [vlf_sequence_number] FROM sys.dm_db_log_info (DB_ID (N'NewDB'));
sys.dm_db_log_info
に注意してください DMVはSQLServer2016SP2で追加されました。その前(そして今日はまだ存在しているため)、文書化されていないDBCC LOGINFO
を使用できます。 コマンドですが、選択リストを指定することはできません。DBCC LOGINFO(N'NewDB');
を実行するだけです。 VLFシーケンス番号はFSeqNo
にあります 結果セットの列。
とにかく、sys.dm_db_log_info
をクエリした結果 だった:
file_id vlf_begin_offset vlf_size_mb vlf_sequence_number ------- ---------------- ----------- ------------------- 2 8192 1.93 37 2 2039808 1.93 0 2 4071424 1.93 0 2 6103040 2.17 0
最初のVLFは、ログファイルのオフセット8,192バイトから始まることに注意してください。これは、トランザクションログを含むすべてのデータベースファイルに、最初の8KBを占有し、ファイルに関するさまざまなメタデータを格納するファイルヘッダーページがあるためです。
では、SQL Serverが最初のVLFシーケンス番号に1ではなく37を選択するのはなぜですか? model
で最大のVLFシーケンス番号を見つけます データベースを作成し、新しいデータベースの場合、トランザクションログの最初のVLFは、その番号に1を加えたものをシーケンス番号として使用します。なぜこのアルゴリズムが時間の霧の中で選ばれたのかはわかりませんが、少なくともSQLServer7.0以降はそうなっています。
それを証明するために、私はこのコードを実行しました:
SELECT MAX ([vlf_sequence_number]) AS [Max_VLF_SeqNo] FROM sys.dm_db_log_info (DB_ID (N'model'));
結果は次のとおりです。
Max_VLF_SeqNo -------------------- 36
これで完了です。
VLFとその使用方法についてはまだまだ議論がありますが、今のところ、各VLFにはシーケンス番号があり、VLFごとに1つずつ増加していることを知っていれば十分です。
ログブロック
各VLFには小さなメタデータヘッダーが含まれ、残りのスペースはログブロックで埋められます。各ログブロックは512バイトで始まり、512バイト単位で最大サイズ60KBまで増加します。この時点で、ディスクに書き込む必要があります。次のいずれかが発生した場合、ログブロックが最大サイズに達する前にディスクに書き込まれる可能性があります。
- トランザクションはコミットされ、遅延耐久性はこのトランザクションに使用されないため、トランザクションを耐久性にするためにログブロックをディスクに書き込む必要があります
- 遅延耐久性が使用されており、バックグラウンドで「現在のログブロックをディスクにフラッシュ」する1msタイマータスクが起動します
- データファイルページがチェックポイントまたはレイジーライターによってディスクに書き込まれています。現在のログブロックには、これから書き込まれるページに影響を与える1つ以上のログレコードがあります(ログ先行書き込みは保証)
ログブロックは、データベースを変更するトランザクションによって作成された順序でログレコードを格納する可変サイズのページのようなものと見なすことができます。各トランザクションのログブロックはありません。複数の同時トランザクションのログレコードをログブロックに混在させることができます。これは、単一のトランザクションのすべてのログレコードを検索する必要がある操作に問題をもたらすと思われるかもしれませんが、トランザクションのロールバックがどのように機能するかについては後の投稿で説明するので、そうではありません。
さらに、ログブロックがディスクに書き込まれる場合、コミットされていないトランザクションからのログレコードが含まれている可能性があります。クラッシュリカバリの仕組みのため、これも問題ではありません。これは、シリーズの将来の良い投稿です。
ログシーケンス番号
ログブロックのIDはVLF内にあり、1から始まり、VLF内の新しいログブロックごとに1ずつ増加します。ログレコードには、ログブロック内のIDもあり、1から始まり、ログブロック内の新しいログレコードごとに1ずつ増加します。したがって、トランザクションログの構造階層内の3つの要素すべてにIDがあり、それらはログシーケンス番号と呼ばれる3つの識別子にまとめられます。 、より一般的には単に LSNと呼ばれます 。
LSNは、<VLF sequence number>:<log block ID>:<log record ID>
として定義されます。 (4バイト:4バイト:2バイト)そして単一のログレコードを一意に識別します。 VLFシーケンス番号は永久に増加するため、これは増え続ける識別子です。
グラウンドワークが完了しました!
VLFについて知ることは重要ですが、私の意見では、LSNはトランザクションのロールバックとクラッシュリカバリが構築される基礎であり、LSNは次のように何度も出現するため、SQLServerのロギングの実装について理解するための最も重要な概念です。シリーズを進めていきます。次の投稿では、ログの切り捨てとトランザクションログの循環的な性質について説明します。これは、VLFとそれらがどのように再利用されるかに関係しています。