1. 論理ストレージ構造:
テーブル スペース (ibd ファイル): Mysql インスタンスは、レコード、インデックス、およびその他のデータを格納するための複数のテーブル スペースに対応できます。
セグメント: データ セグメント、インデックス セグメント、ロールバック セグメント、
InnoDB はインデックス構成テーブルであり、データ セグメントは B+ ツリーのリーフ ノードであり、インデックス セグメントは B+ ツリーの非リーフ ノードであり、セグメントは複数の (エクステント) 領域を管理するために使用されます。
エリア: テーブルスペースの単位構造. 各エリアのサイズは 1M. デフォルトでは、InnoDB ストレージ エンジンのページ サイズは 16K です.つまり、1 つのエリアに 64 個の連続したページがあります.
ページ: InnoDB ストレージ エンジンのディスク管理の最小単位です. 各ページ サイズは 16KB. ページの連続性を確保するために、InnoDB ストレージ エンジンは毎回ディスクから 4 ~ 5 の領域を適用します.
行: InnoDB ストレージ エンジンは行ごとに格納されます
Trx_id: レコードが変更されるたびに、対応するトランザクションの ID が trx_id 隠し列に割り当てられます。これは、最後の操作トランザクションの ID です。
Roll_pointer: レコードが変更されるたびに、古いバージョンが元に戻すログに書き込まれ、この非表示の列はポインタに相当し、レコードの変更前の情報を見つけることができます
2. InnoDB アーキテクチャ
2.1 メモリ構造
2.1.1 BufferPool: バッファプール
バッファプールは、ディスク上で頻繁に操作される実データをキャッシュできるメモリ上の領域であり、追加、削除、変更、およびクエリを実行する場合、バッファプール内のデータが最初に操作されます (存在しない場合)。この時点でバッファー内のデータは、ディスクとキャッシュからロードされます)、特定の頻度またはルールでディスクに更新して、ディスク IO の数を減らし、処理を高速化します。
バッファがないと、すべての追加、削除、変更、およびクエリ操作がディスク領域で実行され、多数のディスク IO が発生します.ビジネスでは、ディスク IO はランダム IO であり、非常に時間がかかり、非常に時間がかかります。パフォーマンスを消費するため、ディスク IO を可能な限り削減する必要があります。
バッファ プールの処理単位はページであり、最下層はリンク リスト データ構造を使用してページを管理し、状態に応じて、ページは次の 3 つのタイプに分けられます。
- フリーページ:フリーページ、未使用
- きれいなページ: 使用されたページ、データは変更されていません
- ダーティ ページ: ダーティ ページ、使用済みページ、データが変更されており、データがディスク内のデータと一致していない
2.2.2 バッファーの変更: バッファーを変更する
DML文の実行時、データページがBuffer Poolにない場合、ディスクは直接操作されませんが、現在のデータ変更はChange Buffer(チェンジバッファ)に格納され、データが読み込まれると、 future を作成し、データをマージしてバッファ プールに復元し、マージされたデータをディスクに更新します。
機能: すべてのディスク操作は大量のディスク IO を引き起こします.ChangeBuffer を使用すると、マージ プロセスをバッファー プールで実行できるため、ディスク IO が大幅に削減されます。
2.2.3 適応ハッシュインデックス:
適応型ハッシュ インデックスは、Buffer Pool (バッファ プール) データのクエリを最適化するために使用されます. InnoDB は、テーブルの各インデックス ページのクエリを監視し、ハッシュ インデックスが速度を改善できることがわかった場合、ハッシュ インデックスを作成します. 注: アダプティブ ハッシュ インデックスは、手動の介入なしで、状況に応じてシステムによって自動的に完成されます。
アダプティブ ハッシュ インデックスには、adaptive_hash_index を有効にするかどうかを設定するフラグ スイッチがあります。
2.2.4 ログバッファ: ログバッファ
ログ バッファ、ログ データ (再実行ログ、元に戻すログ) をディスクに書き込むように保存します。デフォルトは 16MB です。ログは定期的にディスクに更新されます。多数の行のトランザクションを更新、挿入、または削除する必要がある場合は、ログ バッファのサイズを大きくする ディスク IO を節約できます
パラメータ:
InnoDB_log_buffer_size: バッファサイズ、
InnoDB_flush_log_at_trx_commit: ログがディスクにフラッシュされるとき (このパラメーターには 1、0、2 の 3 つの値があります)
1. トランザクションがコミットされるたびに、ディスクにフラッシュされます
0. ログは毎秒書き込まれ、ディスクにフラッシュされます
2. 各トランザクションがコミットされた後、毎秒ディスクに更新されます
2.2 ディスク構造
2.2.1 システムテーブルスペース: システムテーブルスペースは、メモリ構造の[Change Buffer ]の格納領域です。パラメータ: innodb_data_file_path
2.2.2 File-Per-Table テーブルスペース: 各テーブル ファイルのテーブルスペースには、単一の InnoDB テーブルのデータとインデックスが含まれ、ファイル システム上の単一のデータ ファイルに格納されます。パラメータ: innodb_file_per_table (デフォルトで有効)
2.2.3 一般表領域:表の作成時に指定できる create TableSpace 構文を使用して作成する必要がある一般表領域。(表領域を自分で手動で作成し、新しい表を作成するときに手動で作成した表領域を指定できるのと同じです)
2.2.4 元に戻すテーブルスペース: 元に戻すテーブルスペース。MySQL インスタンスは、初期化中に 2 つのデフォルトの元に戻すテーブルスペース (デフォルトは 16MB) を自動的に作成し、元に戻すログ ログを保存します。
2.2.5 一時テーブルスペース: 一時テーブルスペース、InnoDB はセッション一時テーブルスペースとグローバル一時テーブルスペースを使用して、ユーザーが作成した一時テーブル データなどを格納します。
2.2.6 ダブルライト バッファ ファイル: ダブルライト バッファInnoDB エンジンは、データ ページをバッファ プールからディスクにフラッシュする前に、まずデータ ページをダブルライト バッファ ファイルに書き込みます。
2.2.7 REDO ログ: トランザクションの永続化を実現する REDO ログは、REDO ログ バッファ (REDO バッファ)とREDO ログ ファイル (REDO ログ)で構成され、前者はメモリ上、後者はディスク上にあります。トランザクションがコミットされると、すべての変更情報がログに記録されます。ログは、ダーティ ページをディスクにフラッシュするときにエラーが発生したときにデータの回復に使用されます。
2.3 バックグラウンドスレッド
機能: InnoDB バッファー プール内のデータを適切なタイミングでディスク ファイルに更新します。
2.3.1 マスタースレッド
コア バックグラウンド スレッドは、他のスレッドのスケジューリングを担当し、バッファー プール内のデータをディスクに非同期的に更新してデータの整合性を維持することも担当します. これには、ダーティ ページの更新、キャッシュのマージと挿入、および取り消しページのリサイクルも含まれます.
2.3.2 IO スレッド
InnoDB ストレージ エンジンでは、AIO は IO 要求を処理するために広く使用されており、データベースのパフォーマンスを大幅に向上させることができ、IO スレッドは主にこれらの IO 要求のコールバックを担当します。
2.3.3 スレッドのパージ
主にトランザクションが提出したアンドゥログをリサイクルするために使用されます. トランザクションがコミットされた後, アンドゥログは使用されない可能性があるため, リサイクルに使用されます.
2.3.4 ページクリーナースレッド
マスター スレッドがダーティ ページをディスクにフラッシュするのを支援するスレッド。これにより、マスター スレッドの作業負荷を軽減し、ブロックを減らすことができます。
3. 経営理念
トランザクションとは操作の集まりです。分割できない作業単位です。トランザクションは、システム全体に対して操作要求を送信または取り消します。これらの操作は、同時に成功または失敗します。
1. 原子性 トランザクションは分割できない最小単位とみなされなければならない. トランザクション全体のすべての操作は、成功するか、すべて失敗するかのいずれかである. トランザクションの場合、一部の操作のみを実行することは不可能である.
2. 一貫性 (Consistency) トランザクションを実行する前にデータベースが一貫していれば、トランザクションを実行した後もデータベースは一貫しています。
3. 分離 トランザクション操作は、相互に影響を与えることなく、独立して透過的です。トランザクションは独立して実行されます。これは通常、ロックを使用して実現されます。トランザクション処理の結果が他のトランザクションに影響を与える場合、他のトランザクションは取り消されます。トランザクションを 100% 分離するには、速度を犠牲にする必要があります。
4. 永続性 (Durability) トランザクションがコミットされると、その結果は永続的です。システム障害が発生しても、復旧できます。
原子性、一貫性、耐久性は、redolog と undo ログによって制御されます。
分離はロックと MVCC によって制御されます
—> 永続性は REDO ログによって保証されます
REDOログ:トランザクションの永続性を実現するREDOログ. REDOログ(REDOバッファ)とREDOログ(REDOログ)からなる.前者はメモリ上にあり,後者はディスク上にある.トランザクションがコミットされた後,すべて変更情報はログに記録されます。これは、ダーティ ページをディスクにフラッシュするときにエラーが発生した場合のデータ リカバリに使用されます。
説明: この図は、トランザクションがコミットされた後にトランザクションの永続性を確保するための InnoDB の処理メカニズムを示しています. まず、トランザクションがコミットされた後、トランザクションはメモリ構造内のバッファープール内の対応するデータページに移動して、データ. 操作を待ち、操作が完了した後、メモリ内のトランザクションはこの時点で実行されましたが、時間内にディスクに更新されていません.現在のメモリ内の更新されたデータページはダーティページと呼ばれます.バッファプールで操作が実行されると、メモリ内のデータページ すべての操作は領域内の Redolog バッファに記録され、バックグラウンドスレッドによってディスク内の Redo ログに定期的に更新されます。エラーは、バッファ プール内のデータがディスクに更新されるときに発生し、データはディスク リカバリの REDO ログを介して処理できます。バッファー プールのデータがディスクに正しく同期されている場合、ディスク内の再実行ログは役に立たないため、ディスク内の 2 つの再実行ログが相互にコピーされ、タイムリーな更新が行われます。最初にログを書き込んでからデータを同期するこの方法は、WAL (Write-Ahead Log) と呼ばれます。
それでは、最初に Redolog Buffer に書き込み、次にそれを Redo Log に転送するのはなぜでしょうか。各トランザクションの後に、データを Buffer Pool からディスクに更新するだけで十分ではないでしょうか? ここに問題があります. トランザクション内のデータページに対する操作のほとんどはランダムです. 各トランザクションがすぐにディスクにフラッシュされると, 複数のディスク IO が生成され, 多くのパフォーマンスが消費されます. そのため Redolog を渡すとデータが保証されます.このように持続します。
—> 元に戻すログによって原子性が保証されます
元に戻すログ:ロールバック ログ。データが変更される前に情報を記録するために使用されます。役割には、ロールバックと MVCC (複数バージョン制御の同時実行) を提供することが含まれます。
アンドゥログとリドゥログは物理的なログを別々に記録します. これは論理的なログです. レコードが削除されると, 対応する挿入レコードがアンドゥログに記録されると考えられます. レコードが更新されると,対応するレコードが記録されます更新レコード、ロールバックを実行すると、アンドゥ ログ内の論理レコードから対応する内容を読み取り、ロールバックできます。
Undo ログの破棄:トランザクションが実行されると生成されます. トランザクションがコミットされると、Undo ログはすぐには削除されません. これらのログは MVCC にも使用できます.
元に戻すログ ストレージ:セグメントの形式で管理および記録され、1024 個の元に戻すログ セグメントを含むロールバック ロールバック セグメントに格納されます。
4、MVCC
4.1 コンセプト
MVCCとは?
MVCC は、データベースに同時にアクセスする際に複数のバージョンのデータを管理することで、データの書き込み時に書き込みロックを追加する必要があるためにデータの読み取り要求がブロックされ、データの書き込み時にデータが読み取れないという問題を回避するためのものです。
簡単に言えば、MVCC はデータの履歴バージョンを保存し、比較したデータのバージョン番号に従ってデータを表示するかどうかを決定し、読み取りロックを追加せずにトランザクションの分離効果を実現し、最終的にデータを読み取ることができます。同時に変更、データを変更するときに同時に読み取ることができるため、トランザクションの同時実行パフォーマンスが大幅に向上します。
4.2 InnoDB MVCC 実装のコア知識ポイント
4.2.1 トランザクションのバージョン番号
各トランザクションが開始される前に、自己増加するトランザクション ID がデータベースから取得され、トランザクションの実行順序はトランザクション ID から判断できます。
4.2.2 表の隠し列
DB_TRX_ID | データ トランザクションのトランザクション ID を記録します。 |
DB_ROLL_PTR | 元に戻すログ内の以前のバージョン データの位置ポインターへのポインター。 |
DB_ROW_ID | 非表示の ID。クラスター化インデックスとして適切なインデックスを持たないテーブルを作成する場合、非表示の ID を使用してクラスター化インデックスが作成されます。 |
4.2.3 元に戻すログ
元に戻すログは、主にデータが変更される前のログを記録するために使用されます. テーブル情報が変更される前に、データは元に戻すログにコピーされます. トランザクションがロールバックされると、元に戻すログのデータを復元できます.
Undo ログの目的
(1) トランザクションのロールバック時の原子性と一貫性を保証する トランザクションのロールバック時に、アンドゥログデータを復旧に利用することができます。
(2) MVCC スナップショットの読み取りに使用されるデータ MVCC マルチバージョン コントロールでは、アンドゥ ログの履歴バージョン データを読み取ることにより、異なるトランザクション バージョン番号が独自の独立したスナップショット データ バージョンを持つことができます。
4.2.4 トランザクションのバージョン番号とテーブルの隠しカラムとアンドゥログの関係
データ変更シミュレーション プロセスを使用して、トランザクションのバージョン番号、非表示の列、および取り消しログの関係を理解します。
(1) まず元のデータテーブルを用意する
(2) トランザクション A の開始: user_info テーブルで update user_info set name = "Li Si" where id=1 を実行すると、次の処理が実行されます。
1.まず取引番号104を取得する |
2. user_info テーブルの変更前のデータを undo ログにコピーします。 |
3. user_info テーブル id=1 のデータを変更します |
4. 変更されたデータ トランザクション バージョン番号を現在のトランザクション バージョン番号に変更し、DB_ROLL_PTR アドレスをアンドゥ ログ データ アドレスにポイントします。 |
(3) 最終的な実行結果を図に示します
4.2.5 undolog バージョン チェーン
異なるトランザクションまたは同じトランザクションで同じレコードを変更すると、レコードの元に戻すログがレコード バージョンのリンク リストを生成します. リンク リストの先頭は最新の古いレコードであり、リンク リストの末尾は最も古い古いレコードです.記録。
4.2.6 読み取りビュー
各トランザクションが InnoDB で開かれると、1 つ取得されます (読み取りビュー)。このコピーは主に、現在のデータベース システムでアクティブな (コミットされていない) トランザクションの ID 番号を保存します。実際、簡単に言えば、このコピーは、このトランザクションからは見えないシステム内の他のトランザクション ID のリストを保存します。(各トランザクションが開かれると、ID が割り当てられ、増分されるため、最新のトランザクションの ID 値が大きくなります)
つまり、特定のトランザクションのスナップショット読み取りを実行するときに、そのレコードの Read View 読み取りビューを作成し、それを条件と比較して、現在のトランザクションが有効かどうかを判断します。どのバージョンのデータが最新の現在のデータであるか、またはこの行に記録されている取り消しログ内の特定のバージョンのデータであるかを確認できます。
読み取りビューは可視化アルゴリズムに従います。主に、変更するデータの最新レコードの DB_TRX_ID (つまり、現在のトランザクション ID) を取り出し、それをシステム内の他のアクティブなトランザクションの ID (読み取りビューによって維持される) と比較します。 )、DB_TRX_ID が続く場合、読み取りビューの属性がいくつかの比較を行いましたが、これは可視性に準拠していません。次に、DB_ROLL_PTR ロールバック ポインターを使用して Undo ログの DB_TRX_ID を取り出し、それらを再度比較します。つまり、の DB_TRX_ID をトラバースします。特定の条件を満たす DB_TRX_ID が見つかるまで、リンクされたリスト (チェーンの先頭からチェーンの最後まで、つまり、最新の変更とチェックから) を検索し、この DB_TRX_ID が配置されている古いレコードが、現在のトランザクションが確認できる最新の古いバージョン
読み取りビューのいくつかの重要なプロパティ:
m_ids: 現在のシステムでアクティブな (コミットされていない) トランザクション バージョン番号セット |
min_trx_id: アクティブなトランザクション ID の最小値 |
max_trx_id: 事前に割り当てられたトランザクション ID、現在の最大トランザクション ID+1 (トランザクション ID は自己インクリメントであるため) |
Creator_trx_id: 現在の読み取りビューのトランザクション バージョン番号を作成します |
ビュー一致条件の読み取り:
1.データトランザクションID==creator_trx_id
確立された場合、このバージョンにアクセスでき、データが現在のトランザクションによって変更されたことを示します
2. データトランザクションIDが<min_trx_idの場合、表示されます
データ トランザクション ID が読み取りビューの最小アクティブ トランザクション ID より小さい場合、データは現在のトランザクションが開始される前に既に存在していたことが確実であるため、表示できます。
3. データトランザクション ID>=max_trx_id は表示されません
読み取りビューでデータ トランザクション ID が現在のシステムの最大トランザクション ID より大きい場合は、現在の読み取りビューが作成された後にデータが生成されることを意味するため、データは表示されません。
4. min_trx_id<=データ トランザクション ID<max_trx_id の場合、アクティブなトランザクション セット trx_ids と一致します。
データのトランザクション ID が最小のアクティブなトランザクション ID よりも大きく、システムの最大のトランザクション ID 以下である場合、この状況は、現在のトランザクションが開始されたときにデータが送信されていない可能性があることを示しています。
したがって、この時点で、データのトランザクション ID を現在の読み取りビューのアクティブなトランザクション セット trx_ids と一致させる必要があります。
ケース 1: trx_ids コレクションにトランザクション ID が存在しない場合 (読み取りビューが生成された時点でトランザクションがコミットされていることを意味します)、この場合のデータを表示できます。
ケース 2: トランザクション ID が trx_ids に存在する場合、読み取りビューが生成されたときにデータが送信されなかったことを意味しますが、データのトランザクション ID が Creator_trx_id と等しい場合、データが作成者によって生成されたことを意味します。現在のトランザクション自体、およびそれ自体によって生成されたデータはそれ自体で見ることができるため、この場合、データも表示できます。
ケース 3: トランザクション ID が trx_ids に存在し、creator_trx_id と等しくない場合は、読み取りビューが生成されたときにデータが送信されていないことを意味し、それ自体が生成されていないため、この場合はデータを表示できません。 .
5. 読み取りビューの条件が満たされない場合、undo ログからデータを取得します
データのトランザクション ID が読み取りビュー条件を満たさない場合、データの履歴バージョンがアンドゥ ログから取得され、その後、データの履歴バージョンのトランザクション番号が読み取りビュー条件と一致するまでピースが作成されます。条件を満たす履歴データが見つかった場合、または見つからない場合は空の結果を返します。
4.3 MVCCを実装するInnoDBの原理
4.3.1 MVCC 実装プロセスのシミュレーション
以下では、2 つの同時トランザクションを開くことにより、MVCC のワークフローをシミュレートします。
(1) user_info テーブルを作成し、初期化データを挿入する
(2) トランザクション A とトランザクション B が同時に user_info を変更してクエリする
トランザクション A: update user_info set name = "Lisi"
トランザクション B: select * from user_info where id=1
質問:
最初にトランザクション A を開始し、トランザクション A がデータを変更した後、トランザクション B を実行しますが、コミットはしません。最終的な返品結果は何ですか。
実行フローは次のとおりです。
上図の実行フローの説明:
1. トランザクション A: トランザクションを開始するには、まずトランザクション番号 102 を取得します。
2. トランザクション B: トランザクションを開き、トランザクション番号 103 を取得します。
3. トランザクション A: 操作を変更するには、最初に元のデータを取り消しログにコピーしてからデータを変更し、トランザクション番号と最後のデータ バージョンのアドレスを取り消しログにマークします。
4. トランザクション B: このとき、トランザクション B は読み取りビューを取得し、対応する読み取りビューの値は次のとおりです。
5. トランザクションB: クエリステートメントを実行すると、この時点でトランザクション A の変更されたデータが取得されます
6. トランザクション B: 読み取りビューとデータを一致させる
読み取りビューの表示条件が満たされていないことが判明したため、過去のバージョンのデータを undo lo から取得し、読み取りビューと照合して、最終的に返されたデータは次のとおりです。
4.4 スナップショットの読み取りと現在の読み取り
現在読んでいる:
What is read is the latest version of the record. 読み取るときは、他の同時実行トランザクションが現在のレコードを変更できないことを確認する必要があり、読み取ったレコードはロックされます。select ... 共有モードでのロック (共有ロック)、select ... for update、update、insert、delete (排他的ロック) などの日常的な操作はすべて現在の読み取りです。
スナップショット読み取り:
単純な選択 (ロックなし) は、スナップショットの読み取りです. スナップショットの読み取りは、記録されたデータの可視バージョンを読み取ります.これは履歴データである可能性があります. ロック解除は非ブロッキングロックです.
Read Committed: 選択するたびに、スナップショットの読み取りが生成されます
Repeatable Read: トランザクション開始後の最初の select ステートメントで、スナップショットが読み取られます。
シリアライズ可能: スナップショットの読み取りは現在の読み取りに縮退します
データベースの同時実行シナリオには、次の 3 つのタイプがあります。
read-read: 問題はなく、同時実行制御も必要ありません
読み取り/書き込み: スレッド セーフの問題があり、トランザクション分離の問題が発生する可能性があり、ダーティ リード、ファントム リード、繰り返し不可能なリードが発生する可能性があります。
書き込み-書き込み: スレッド セーフの問題があり、最初のカテゴリなど、更新が失われる問題が発生する可能性があります