MySQL InnoDB ストレージ エンジンの詳細

MySQL InnoDB ストレージ エンジンの詳細

序文

MySQL では、InnoDB はストレージ エンジン レイヤーに属し、プラグインとしてデータベースに統合されます。 MySQL 5.5.8 以降では、InnoDB がデフォルトのストレージ エンジンになります。 InnoDB ストレージ エンジンはトランザクションをサポートし、主に OLTP アプリケーション向けに設計されています。主な機能には、トランザクションのサポート、高同時実行性をサポートする行ロック設計、外部キーのサポート、自動クラッシュ リカバリ、テーブル構造を整理するためのクラスター化インデックスなどがあります。

システムアーキテクチャ

InnoDB ストレージ エンジンは、メモリ プール、バックグラウンド スレッド、ディスク ストレージの 3 つの部分で構成されます。

スレッド

InnoDB はマルチスレッド モデルを使用しており、バックグラウンドではさまざまなタスクの処理を担当する複数のスレッドが存在します。

マスタースレッド

マスター スレッドはコア バックグラウンド スレッドであり、主にバッファー プール内のデータをディスクに非同期的に更新してデータの一貫性を確保する役割を担います。ダーティ ページの更新、マージ挿入バッファ、UNDO ページ リサイクルなどが含まれます。

IO スレッド

InnoDB ストレージ エンジンでは、書き込み IO 要求を処理するために非同期 IO (Async IO) が広く使用されています。IO スレッドの主な役割は、これらの IO 要求のコールバックを担当することです。

スレッドの削除

トランザクションがコミットされた後、トランザクションが使用する UNDO ログは不要になる可能性があるため、割り当てられて使用された UNDO ページを再利用するにはパージ スレッドが必要になります。 InnoDB は複数のパージ スレッドをサポートしており、これにより UNDO ページの回復が高速化され、CPU 使用率が向上し、ストレージ エンジンのパフォーマンスが向上します。

ページクリーナースレッド

ページ クリーナー スレッドの役割は、マスター スレッドのダーティ ページ リフレッシュ操作を置き換えることです。その目的は、元のマスター スレッドの作業とユーザー クエリ スレッドのブロックを減らし、InnoDB ストレージ エンジンのパフォーマンスをさらに向上させることです。

メモリ

InnoDB ストレージ エンジンのメモリ構造

バッファプール

InnoDB ストレージ エンジンはディスク ストレージに基づいており、その中のレコードをページ単位で管理します。ただし、CPU 速度とディスク速度の差により、ディスクベースのデータベース システムでは通常、バッファー プール レコードを使用してデータベースの全体的なパフォーマンスを向上させます。

バッファ プールは実際にはメモリの速度を使用して、ディスク速度の遅さがデータベースのパフォーマンスに与える影響を補正します。データベースが読み取り操作を実行すると、ディスク上のページはまずバッファ プールに配置されます。次に同じページが読み取られるときには、キャッシュとして機能するバッファ プールからページ データが最初に取得されます。

データ変更操作では、まずバッファー プール内のページ データが変更され、次にチェックポイントと呼ばれるメカニズムを使用してディスクに更新されます。

バッファ プールのサイズは、データベースの全体的なパフォーマンスに直接影響します。InnoDB ストレージ エンジンの場合、バッファ プールの構成は、パラメータ innodb_buffer_pool_size によって設定されます。バッファ プールの構成を表示するには、SHOW VARIABLES LIKE 'innodb_buffer_pool_size' コマンドを使用します。

mysql> 'innodb_buffer_pool_size' のような変数を表示 \G
************************** 1. 行 ****************************
変数名: innodb_buffer_pool_size
 値: 134217728
セット内の1行(0.01秒)

バッファ プールにキャッシュされるデータ ページの種類には、インデックス ページ、UNDO ページ、挿入バッファ、アダプティブ ハッシュ インデックス、InnoDB ロック情報、データ ディクショナリ情報などがあります。インデックス ページとデータ ページは、バッファ プールの大部分を占めます。

REDOログバッファ

バッファ プール内のページ データがディスクよりも新しい場合は、新しいデータをディスクにフラッシュする必要があります。 InnoDB は、先行書き込みログ戦略を使用してデータを更新します。つまり、トランザクションがコミットされると、最初に REDO ログ バッファに書き込まれます。REDO ログ バッファは一定の頻度でリセット ログ ファイルに更新され、その後、チェックポイント メカニズムに従ってダーティ ページがディスクに更新されます。

REDO ログ バッファを非常に大きく設定する必要はありません。通常、8M でほとんどのアプリケーション シナリオに対応できます。 REDO ログは、更新をトリガーする次の 3 つの状況をサポートします。

  • マスタースレッドは、1秒ごとにREDOログバッファをREDOログファイルにフラッシュします。
  • トランザクションがコミットされるたびに、REDOログバッファをREDOログファイルにフラッシュする
  • 再実行ログバッファプールの残りスペースが1/2未満になると、再実行ログバッファは再実行ログファイルにフラッシュされます。


追加メモリプール

InnoDB ストレージ エンジンでは、メモリはメモリ ヒープと呼ばれる方法で管理されます。一部のデータ構造自体にメモリを割り当てる場合、追加のメモリプールから適用する必要があります。この領域のメモリが不足する場合は、バッファプールから適用されます。

ロック

InnoDB でサポートされているロックは次のとおりです。

  • 共有ロックと排他ロック
  • 意図ロック
  • レコードロック
  • ギャップロック
  • 自動増分ロック

共有ロックと排他ロック

InnoDB エンジンは、共有 (S) ロックと排他 (X) ロックという 2 つの標準的な行レベル ロックを実装します。共有ロックでは、ロックを保持するトランザクションがデータ行を読み取ることができ、排他ロックでは、トランザクションがレコード行を書き込むことができます。

トランザクションが共有ロックを保持している場合、他のトランザクションはこのレコード行の共有ロックを取得できますが、このレコード行の排他ロックを取得することはできません。トランザクションが行の排他ロックを取得すると、他のトランザクションはこの行の共有ロックと排他ロックを取得できなくなります。

意図ロック

InnoDB では、インテンション ロックはテーブル レベルのロックであり、共有ロックと排他ロックに分けられます。

  • 意図的な共有ロック: 行の共有ロックを取得する
  • 意図的排他ロック: 行の排他ロックを取得する

トランザクションは、共有/排他ロックを取得する前に、まず意図的な共有/排他ロックを取得する必要があります。意図的なロックは、テーブル上の他の操作をブロックしません。行に対して共有ロックまたは排他ロックを取得することを他のトランザクションに通知するだけです。

レコードロック

レコード ロックはインデックスのロックです。レコード自体ではなく、レコードのインデックスをロックします。現在のテーブルにインデックスがない場合、InnoDB はテーブルに対して非表示のクラスター化インデックスを作成し、レコード ロックはこの非表示のクラスター化インデックスをロックします。

ギャップロック

ギャップ ロックは、レコード ロックと同様に、インデックスに対しても作用します。違いは、レコード ロックは 1 つのインデックス レコードに対してのみ作用するのに対し、ギャップ ロックはインデックスの範囲をロックできることです。 InnoDB のギャップ ロックの唯一の機能は、他のトランザクションによるデータの挿入を防ぎ、ファントム リードを防止することです。

自動増分ロック

自動インクリメント ロックは、自動インクリメント列を含む挿入操作でのみ機能する特別なテーブル レベルのロックです。トランザクションがデータを挿入している場合、他のトランザクションはトランザクション全体が挿入操作を完了するまで待機し、その後ロックを取得して挿入操作を実行する必要があります。

取引


トランザクションは OLTP データベースの最も重要な機能です。トランザクションについて話すときは、ACID の 4 つの基本特性について言及する必要があります。

  • 原子性: トランザクションにおける作業の最小単位。すべてが成功するか、すべてが失敗するかのいずれかです。
  • 一貫性: トランザクションの開始後および終了後も、データベースの整合性は損なわれません。
  • 分離: 異なるトランザクションは互いに影響を及ぼしません。分離レベルは RU (コミットされていない読み取り)、RC (コミットされた読み取り)、RR (繰り返し読み取り)、および SERIALIZABLE (シリアル化可能) の 4 つです。
  • 耐久性: トランザクションがコミットされると、データへの変更は永続的になり、システムに障害が発生しても失われません。

InnoDB の原子性、永続性、一貫性は、主に Redo ログ、Undo ログ、およびコミット時の強制ログのメカニズムによって実現されます。 Redo ログはクラッシュ時にデータを回復するために使用され、Undo ログはトランザクションの影響を元に戻すために使用されます。また、マルチバージョン管理にも使用できます。コミット時の強制ログ メカニズムにより、トランザクションがコミットされた後も Redo ログが保持されることが保証されます。分離はロックと MVCC によって確保されます。

分離レベル

MySQL には、次の 4 つのトランザクション分離レベルがあります。

  • コミットされていない読み取り
  • コミットされた読み取り
  • 繰り返し読み取り
  • シリアル化可能

4 つの分離レベルを理解する前に、他の 3 つの用語を理解する必要があります。

  • ダーティリード

トランザクション a はトランザクション b がまだコミットしていないデータを読み取りますが、何らかの理由でトランザクション b がロールバックされます。このように、トランザクション a によって読み取られたデータは使用できず、異常な結果が発生します。

  • 繰り返し不可能な読み取り

あるデータは a のトランザクション サイクル中に複数回クエリされ、同時にトランザクション b でこのデータが更新または削除されます。その場合、トランザクション a の各クエリの結果は異なる可能性があります。

  • ファントムリード

ファントムリードの結果は、実際には非反復読み取りの結果と同じです。違いは、非反復読み取りは主に他のトランザクションの編集(更新)と削除(削除)操作を実行することです。ファントム リードは主に挿入操作に使用されます。つまり、トランザクションのライフサイクル内で、別のトランザクションの新しく挿入されたデータが照会されます。

コミットされていない読み取り

コミットされていない読み取り。この場合、トランザクション a は別のトランザクション b のコミットされていないデータを見ることができます。この時点でトランザクション b がロールバックされると、トランザクション a はダーティ データを取得します。これがダーティ リードの意味です。

この分離レベルは、通常、MySQL InnoDB では推奨されません。

コミットされた読み取り

コミットされた読み取り: トランザクションによって開始からコミットされるまでの間に行われた変更は、他のトランザクションには表示されません。ダーティ リードの問題は解決されましたが、ファントム リードは依然として存在します。

繰り返し読み取り

繰り返し読み取り: このレベルでは、同じトランザクションで同じレコードを複数回読み取った結果の一貫性が確保されます。InnoDB ストレージ エンジンのファントム読み取り問題と繰り返し不可能な読み取り問題の両方が解決されます。

InnoDB エンジンは、Next-Key Lock を使用してファントム読み取りの問題を解決します。ネクストキー ロックは、行ロックとギャップ ロックの組み合わせです。InnoDB は、インデックス レコードをスキャンするときに、最初に行ロック (レコード ロック) をインデックス レコードに追加し、次にインデックス レコードの両側のギャップにギャップ ロック (ギャップ ロック) を追加します。ギャップ ロックを追加すると、他のトランザクションはこのギャップ内のレコードを変更したり挿入したりできなくなります。

シリアル化可能

Serializable は最も高い分離レベルです。トランザクションを強制的にシリアルに実行することで、ファントム リードの問題を回避します。ただし、Serializable は読み取られるデータ行ごとにロックするため、多数のタイムアウトやロック競合の問題が発生する可能性があります。その結果、同時実行性が大幅に低下します。また、MySQL InnoDB で使用することも推奨されません。

取引を開く

  • 開始、作業開始、取引開始

BEGIN コマンドを実行しても、実際にはエンジン レベルで新しいトランザクションが開始されるわけではなく、現在のスレッドに、明示的に開始されたトランザクションであることを示すマークが設定されるだけです。

  • トランザクション開始 読み取り専用

読み取り専用トランザクションが有効になっている場合、MySQL サーバーはデータ変更の SQL を受信すると、データの変更を直接拒否し、エラーを返します。このエラーはエンジン レイヤーに入りません。

  • トランザクション開始読み取り書き込み

現在のスレッドの読み取り専用状態が true の場合、スーパーユーザーが読み取り/書き込みトランザクションを開始できるようにします。

  • 一貫性のあるスナップショットでトランザクションを開始

トランザクションを開くと、エンジン レイヤーに入り、readview が開きます。この操作は RR 分離レベルでのみ有効です。それ以外の場合はエラーが報告されます。

元に戻すログ

データが変更されると、対応する UNDO ログが記録されます。トランザクションが失敗したりロールバックしたりした場合は、記録された UNDO ログを使用してロールバックできます。 UNDO ログは、変更前のデータイメージを記録する論理ログです。変更中に現在のデータを同時に読み取る必要がある場合は、バージョン情報に基づいて行に記録されたデータの以前のバージョンを分析できます。さらに、Undo ログも永続的に保護する必要があるため、Undo ログによって Redo ログも生成されます。

トランザクションコミット

  1. グローバルトランザクションIDジェネレータを使用してトランザクション番号を生成し、現在の接続のトランザクションポインタ(trx_t)をグローバルコミット済みトランザクションリスト(trx_serial_list)に追加します。
  2. 元に戻すをマークします。このトランザクションが 1 つの UndoPage のみを使用し、使用量がページの 3/4 未満である場合は、このページを TRX_UNDO_CACHED としてマークします。要件を満たしておらず、挿入元に戻す場合は、TRX_UNDO_TO_FREE としてマークします。それ以外の場合、元に戻すが更新元に戻す場合は、TRX_UNDO_TO_PURGE としてマークします。 TRX_UNDO_CACHED としてマークされた元に戻す操作は、エンジンによってリサイクルされます。
  3. 更新の取り消しを undo セグメントの履歴リストに格納し、rseg_history_len (グローバル) を増分します。同時に、ページ上の TRX_UNDO_TRX_NO を更新し、データが削除された場合は delete_mark をリセットします。
  4. update_undo_list から undate undo を削除します。TRX_UNDO_CACHED としてマークされている場合は、update_undo_cached キューに追加します。
  5. mtr_commit (ログの undo/redo がパブリック バッファに書き込まれる) では、これまでのところ、トランザクションはファイル レベルでコミットされています。このとき、システムがクラッシュした場合でも、再起動後にトランザクションをコミットすることができます。次に行うことは、メモリデータのステータスを更新することです (trx_commit_in_memory)
  6. 読み取り専用トランザクションでは、グローバル読み取りビュー リストから読み取りビューを削除し、trx_t 構造体の情報をリセットするだけで済みます。読み取り/書き込みトランザクションでは、まずトランザクション状態を TRX_STATE_COMMITTED_IN_MEMORY に設定し、すべての行ロックを解除して rw_trx_list から trx_t を削除し、グローバル readview リストから readview を削除する必要があります。挿入の取り消しがある場合は、ここで削除します。更新の取り消しがある場合は、Purge スレッドを起動してゴミをクリーンアップします。最後に、次のトランザクションのために trx_t の情報をリセットします。

ロールバック

  • 読み取り専用トランザクションの場合は、直接戻ります。
  • トランザクション全体をロールバックするか、トランザクションの一部をロールバックするかを決定します。部分的なトランザクションの場合は、保持する必要がある Undo ログの数を記録し、余分なものをすべてロールバックします。
  • 更新の元に戻すと挿入の元に戻すから最後の元に戻すを見つけ、この元に戻すからロールバックします。
  • 更新を元に戻す場合は、削除済みとしてマークされたレコードがクリアされ、更新されたデータは最も古いバージョンにロールバックされます。挿入を元に戻す場合は、クラスター化インデックスとセカンダリインデックスを直接削除します。
  • すべての元に戻す操作がロールバックされた場合、または指定された元に戻す操作までロールバックされた場合は、元に戻すログを停止して削除します。

索引

InnoDB エンジンは、インデックス構造として B+ ツリーを使用します。主キー インデックスのリーフ ノードのデータ ドメインには完全なフィールド データが保存され、非主キー インデックスのリーフ ノードには主キーを指す値データが格納されます。

上図は、InnoDB プライマリ インデックス (データ ファイルでもある) の概略図です。リーフ ノードに完全なデータ レコードが含まれていることがわかります。このタイプのインデックスは、クラスター化インデックスと呼ばれます。 InnoDB のデータ ファイル自体は主キーによってクラスタ化されるため、InnoDB ではテーブルに主キーが必要です。明示的に指定されていない場合、MySQL システムはデータ レコードを一意に識別できる列を主キーとして自動的に選択します。そのような列が存在しない場合、MySQL は InnoDB テーブルの暗黙的なフィールドを主キーとして自動的に生成します。このフィールドは 6 バイト長で、長整数型です。

InnoDB のセカンダリ インデックス データ フィールドには、アドレスではなく、対応するレコードのプライマリ キーの値が格納されます。つまり、InnoDB のすべてのセカンダリ インデックスは、データ フィールドとしてプライマリ キーを参照します。クラスター化インデックスの実装により、主キーによる検索は非常に効率的になりますが、補助インデックス検索には 2 つのインデックス検索が必要です。最初に補助インデックスを検索して主キーを取得し、次に主キーを使用して主インデックスからレコードを取得します。

結論

この記事では、MySQL InnoDB の多くの機能のうち、ほんの一部を紹介するだけです。興味のある学生は、「MySQL Technology Insider: InnoDB Storage Engine」を読んで、関連する知識をさらに学ぶことができます。

さて、以上がこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM をご愛顧いただきありがとうございます。

以下もご興味があるかもしれません:
  • MySql 最適化のための my.ini 中国語構成スキームの詳細な説明: InnoDB、4GB メモリ、および複数のクエリ
  • MySQL InnoDBストレージエンジンについて簡単に説明します
  • MySQL 学習のまとめ: InnoDB ストレージ エンジンのアーキテクチャ設計の予備的な理解
  • MySQL 学習 (VII): Innodb ストレージ エンジン インデックスの実装原理の詳細説明
  • MySQL ストレージ エンジン MyISAM と InnoDB の違いの概要
  • MySQL 8.0 のメモリ消費の詳細な分析
  • MySQL メモリテーブルと一時テーブルの使用方法の詳細な説明
  • MySQL 8.0 のメモリ関連パラメータの概要
  • MySql でメモリ使用量を削減する方法の詳細な説明
  • MySQL InnoDB ストレージエンジンのメモリ管理の詳細な説明

<<:  JS 面接の質問: forEach はループから抜け出すことができますか?

>>:  VMware に Centos7 をインストールした後に外部ネットワークに ping できない問題を解決する

推薦する

HTML にオーディオファイルを挿入してブラウザで再生する場合の互換性の問題

HTML にオーディオ ファイルを挿入した後 (mp3 ファイルを再生した後) に発生したいくつかの...

OEL7.6 ソースコードから MYSQL5.7 をインストールするチュートリアル

まず、公式サイト https://dev.mysql.com/downloads/mysql/5.7...

HTML コードを書くための 30 のヒント

1. HTMLタグは常に閉じる前のページのソース コードでは、次のような記述がよく見られます。 &l...

Linux におけるシステム入出力管理の詳細な説明

システムの入力と出力の管理1. システムの入力と出力を理解するLinuxシステムでは、1は正しい出力...

Vueにおける仮想DOMの理解のまとめ

これは本質的に、ビュー インターフェース構造を記述するために使用される共通の js オブジェクトです...

webpackコード断片化の実装

目次背景コモンズチャンクプラグイン分割チャンク構成リソースを非同期に読み込む要約する背景高性能なアプ...

CSS3で実装された天気アイコンのアニメーション効果

成果を達成する 実装コードhtml <div class="wrapper"...

Docker環境を構築する簡単な方法

まず、Docker とは何かを理解しましょう。 Docker は、アプリケーションをデプロイするため...

Navicat for MySQL 15 登録とアクティベーションの詳細なチュートリアル

1. Navicat for MySQL 15をダウンロードするhttps://www.navica...

一時ファイルを作成できないために MySQL が起動できない問題を解決する方法

問題の説明最近、仕事中に問題が発生しました。MySQL が起動に失敗しました。エラー ログは次のとお...

Linux でファイルを削除するときに「操作は許可されていません」というプロンプトが表示される場合の対処方法

同僚からよく聞かれるのですが、ファイル/ディレクトリを削除すると「操作は許可されていません」というエ...

JavaScript の Set データ構造の詳細な説明

目次1. セットとは何か2. セットコンストラクタ2.1) 配列2.2) 文字列2.3) 議論2.4...

Window.nameはクロスドメインデータ転送の問題を解決します

<br />原文: http://research.microsoft.com/~hel...

echarts と vue.js を統合する際に発生するいくつかの問題の概要

序文現在、私は Beetlex のデータ分析プラットフォームに取り組んでいます。この製品の開発では、...