MySQLの保存およびクエリ手順
SQLを実行すると、次のプロセスが実行され、データが最終的にファイルの形式で存在することがわかります。
データベースに学生テーブルを作成すると、ファイルシステムに次のファイルが作成されます。
これらのデータは最終的にファイルに保持されますが、このデータはファイル内でどのように編成されていますか?ファイルに1行ずつ追加していますか?実際にはそうではありません。データは実際にはページに格納されます。ページのサイズは16kです。テーブルは多くのページで構成されています。これらのページはB+ツリーを形成します。
テーブルは次のように保存されます
データフォームページの行、ページフォームエリア、およびエリアフォームセグメントにより、管理が容易
ページ:ページはinnodbディスク管理の基本単位であり、各innodbページのサイズは16kです。
エクステント:64の連続したページで構成され、各ページのサイズは16kbです。つまり、各エクステントは約1MBです。
セグメント:一般的なセグメントには、データセグメント(B +ツリーページノード)、インデックスセグメント(B +ツリー非ページノード)、ロールバックセグメントなどが含まれます。
まず、ページがどのようにデータを保存するかを微視的な観点から見てみましょう。
ページの形式は次のとおりです。
名前 | 説明する |
---|---|
ファイルヘッダー | ページの情報を示します |
ヘッダ | ページのステータス情報を示します |
最小および最大レコード | ページ内の最小レコードと最大レコードを表す2つの仮想レコード |
ユーザー記録 | 行レコードのコンテンツを保存する |
フリースペース | ページ内の未使用スペース |
ページディレクトリ | ユーザーレコードのインデックス |
ファイルの終わり | ページが完成しているかどうかを確認します |
データは継続的にユーザーレコードに挿入され、データがいっぱいになると空き領域がなくなります。
ページ内のレコードは、主キーの値に従って小さいものから大きいものへと並べ替えられ、単一リンクリストを形成します。
私が作成したテーブルには主キーがないのですが、テーブル内のデータをどのように整理する必要があるのでしょうか。
- 最初に、テーブルにnull以外の一意のインデックスがあるかどうかを判断します。ある場合は、列が主キーです。
- そうでない場合は、row_idという非表示の列を主キーとして追加します
ページは二重リンクリストで接続されてい
ますページ内のデータを検索する場合、リンクリストを1つずつトラバースする必要がありますか?
もちろんそうではありません。検索率を向上させるために、mysqlはデータをグループ化し、ページディレクトリを使用して各グループの最大レコードのアドレスを記録します。
各グループにはいくつのデータがありますか?
- 最初のグループのレコードは1つのレコードしか持つことができません
- 最後のグループのレコード数は、1〜8の間のみです。
- 残りのグループのレコード数は、1〜8の間のみです。
下の図に示すように
、青い部分は主キーとそれに対応するデータです
レコードを検索するときは、最初にページディレクトリから対応するグループを見つけてから、グループ内のリンクリストをトラバースします。
たとえば、主キーが10で、5つのスロットの数が0、1、2、3、および4であるユーザーレコードを検索したい場合、検索プロセスは次のとおりです。
- まず、スロットの中央のビットは(0 + 4)/ 2=2です。スロット2の最大レコードは8です。スロット2の後ろからレコードを検索し続ける必要があります。
- スロット3とスロット4の間のビットは(3 + 4)/ 2 = 3であり、スロット3の最大レコードは12、12> 10であるため、検索されるレコードはスロット3にあります。
- ただし、ユーザーレコード間のリンクリストは一方向であるため、最初にスロット2の8つのレコードに移動してから、ターゲットレコードが見つかるまでリンクリストに沿ってトラバースを開始できます。
データディレクトリが存在するため、ページ内のデータの検索は高速ですが、テーブル内のデータの検索は依然として低速ですか?結局のところ、リンクリストに沿ってすべてのデータページをトラバースする必要があります
もちろん、MySQLではこれを許可していません。レコード用のディレクトリを作成して検索速度を上げることができるので、ページ用のディレクトリを作成して検索速度を上げることができます。ディレクトリの形式は最小の主キーIDです。各ページとそれに対応するページ番号(ページのアドレス)
ディレクトリも16kbのサイズのデータページに保存されます。したがって、複数のディレクトリが存在する可能性があります。ディレクトリが多すぎる場合は、ディレクトリ用のディレクトリを作成することもできます。下の写真のように、
これは木ではありませんか?リーフノードはレコードを格納し、非リーフノードは主キーと対応するページアドレスを格納します。この木は実際にはB+木です
上の図の例として、テーブル内の主キーが5であるデータをクエリします。クエリプロセスは次のとおりです。
最初にルートディレクトリに移動して確認し、次に30ページに移動して確認し、次に16ページに移動して、最後にレコードを見つけます
次に、問題を分析できるように、マクロの観点からデータのストレージを分析しましょう。
MyISAMを使用してデータを格納する場合、データとインデックスは分離され、対応するレコードのアドレスがB +ツリーに格納されます
。InnoDBを使用してデータを格納する場合、データとインデックスは一緒になります。つまり、クラスター化されたインデックスです。 。もちろん、フィールドの非クラスター化インデックスを作成することもできます
。クラスター化インデックスのリーフノードはユーザーデータを格納し、非クラスター化インデックスのリーフノードはインデックス付きの列値とそれに対応する主キー値を格納します。
主キーを使用してレコードをクエリする場合は、クラスター化インデックスをトラバースするだけで済みます。非クラスター化インデックスを使用してデータをクエリする場合は、最初に非クラスター化インデックスをトラバースしてレコードの主キー値を見つけ、次に主キー値に従ってクラスター化インデックスをトラバースしてデータを取得します。つまり、テーブルを返します。
リファレンスブログ
[1] http://liuqh.icu/2019/04/03/db/innodb-storage/
[2] https://bbs.huaweicloud.com/blogs/317532