Source:The basics of InnoDB space file layout
The physical structure of InnoDB index pages
In On learning InnoDB: A journey to the core, I introduced the innodb_diagrams project to document the InnoDB internals, which provides the diagrams used in this post.
「In On learning InnoDB: A journey to the core」において、私はInnoDBの内部構造を文書化するためのinnodb_diagramsプロジェクトを紹介しました。このプロジェクトは、この記事で使用されている図を提供しています。
InnoDB’s data storage model uses “spaces”, often called “tablespaces” in the context of MySQL, and sometimes called “file spaces” in InnoDB itself. A space may consist of multiple actual files at the operating system level (e.g. ibdata1, ibdata2, etc.) but it is just a single logical file — multiple physical files are just treated as though they were physically concatenated together.
InnoDBのデータストレージモデルでは、「space(スペース)」と呼ばれる単位が使われます。MySQLの文脈ではこれらは「テーブルスペース(tablespace)」と呼ばれ、InnoDB自体の内部では「file space(ファイルスペース)」と呼ばれることもあります。
一つのspaceは、オペレーティングシステムレベルでは複数の実際のファイル(例:ibdata1、ibdata2など)で構成される場合もありますが、論理的には単一のファイルとして扱われます。つまり、複数の物理ファイルは、あたかも物理的に連結されているかのように扱われます。
Each space in InnoDB is assigned a 32-bit integer space ID, which is used in many different places to refer to the space. InnoDB always has a “system space”, which is always assigned the space ID of 0. The system space is used for various special bookkeeping that InnoDB requires.
InnoDBでは、各スペース(テーブルスペースなど)に32ビット整数のスペースIDが割り当てられており、このIDはさまざまな場所でスペースを参照するために使われます。
InnoDBには必ず「system space」が存在し、そのスペースIDは常に0です。
システムスペースは、InnoDBが内部で必要とするさまざまな特別な管理情報を保持するために使われます。
Through MySQL, InnoDB currently only supports additional spaces in the form of “file per table” spaces, which create an .ibd file for each MySQL table. Internally, this .ibd file is actually a fully functional space which could contain multiple tables, but in the implementation with MySQL, they will only contain a single table.
MySQLを通じて利用される場合、InnoDBは現在のところ「file per table」方式による追加のスペースのみサポートしています。
この方式では、各MySQLテーブルごとに.ibdファイルが作成されます。
内部的には、この.ibdファイルは複数のテーブルを含めることができる完全なスペースですが、MySQLの実装では1つのテーブルしか含まれません。
(以下個人の追記)
MySQL 8.0でも「file per table」はデフォルトで有効(innodb_file_per_table=ON)
この設定により、InnoDBで作成されるテーブルは、それぞれ独立した.ibdファイル(例:test.t1ならt1.ibd)として保存される。もし「innodb_file_per_table=OFF」に設定すると、すべてのテーブルがシステムテーブルスペース(ibdata1など)に格納される。ただし、MySQL 8.0の標準的な運用では、file per tableが推奨されている。
mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.021 sec)
-- 表作成
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(100)
) ENGINE=InnoDB;
SELECT
TABLE_SCHEMA AS database_name,
TABLE_NAME AS table_name,
DATA_LENGTH, INDEX_LENGTH
FROM
INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'test_table';
+---------------+------------+-------------+--------------+
| database_name | table_name | DATA_LENGTH | INDEX_LENGTH |
+---------------+------------+-------------+--------------+
| mydb | test_table | 16384 | 0 |
+---------------+------------+-------------+--------------+
1 row in set (0.020 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_DATAFILES;
+------------------------+-------------------------------------------+
| SPACE | PATH |
+------------------------+-------------------------------------------+
| 0x30 | ibdata1 |
| 0x34323934393637323739 | ./undo_001 |
| 0x34323934393637323738 | ./undo_002 |
| 0x31 | ./sys/sys_config.ibd |
| 0x33 | ./mysql/rds_configuration.ibd |
| 0x3133 | ./mysql/rds_global_status_history.ibd |
| 0x3134 | ./mysql/rds_global_status_history_old.ibd |
| 0x3135 | ./mysql/rds_heartbeat2.ibd |
| 0x3137 | ./mysql/rds_sysinfo.ibd |
| 0x34323934393637323737 | ./undo_003 |
| 0x3138 | ./mysql/aurora_s3_load_history.ibd |
| 0x3230 | ./mysql/ro_replica_status_internal.ibd |
| 0x3235 | ./mysql/rds_history.ibd |
| 0x3236 | ./mysql/rds_replication_status.ibd |
| 0x3237 | ./mydb/test_table.ibd |
+------------------------+-------------------------------------------+
15 rows in set (0.022 sec)
(個人の追記ここまで)
Pages
Each space is divided into pages, normally 16 KiB each (this can differ for two reasons: if the compile-time define UNIV_PAGE_SIZE is changed, or if InnoDB compression is used).
各スペース(テーブルスペースなど)はページに分割されており、通常1ページあたり16KiB(16,384バイト)になっています(ただし、UNIV_PAGE_SIZEのコンパイル時定義が変更されている場合や、InnoDBの圧縮機能が使われている場合には異なるサイズになることがあります)。
Each page within a space is assigned a 32-bit integer page number, often called “offset”, which is actually just the page’s offset from the beginning of the space (not necessarily the file, for multi-file spaces).
スペース内の各ページには32ビット整数のページ番号が割り当てられており、これはしばしば「オフセット」とも呼ばれます。このページ番号は、スペースの先頭からのオフセット(ファイルの先頭からのオフセットとは限りません。複数ファイルで構成されるスペースの場合もあります)を表しています。
So, page 0 is located at file offset 0, page 1 at file offset 16384, and so on. (The astute may remember that InnoDB has a limit of 64TiB of data; this is actually a limit per space, and is due primarily to the page number being a 32-bit integer combined with the default page size: 232 x 16 KiB = 64 TiB.)
したがって、ページ0はファイルオフセット0に、ページ1はファイルオフセット16384に、といったように配置されます。
(※注意深い方は、InnoDBには64TiBのデータ容量制限があることを覚えているかもしれませんが、これは実際にはスペースごとの制限であり、主にページ番号が32ビット整数であることと、デフォルトのページサイズ(16KiB)によるものです。2の32乗×16KiB = 64TiBとなります。)
A page is laid out as follows:

Every page has a 38-byte FIL header and 8-byte FIL trailer (FIL is a shortened form of “file”). The header contains a field which is used to indicate the page type, which determines the structure of the rest of the page. The structure of the FIL header and trailer are:
各ページには38バイトのFILヘッダと8バイトのFILトレーラがあります(FILは「file」の略称です)。
ヘッダにはページタイプを示すフィールドが含まれており、この値によってページの残りの構造が決まります。
FILヘッダとトレーラの構造は以下の通りです。

The FIL header and trailer contain the following structures (not in order):
FILヘッダとトレーラには以下の構造が含まれます(順不同です)。
- The page type is stored in the header. This is necessary in order to parse the rest of the page data. Pages are allocated for file space management, extent management, the transaction system, the data dictionary, undo logs, blobs, and of course indexes (table data).
- ページタイプはヘッダに格納されます。これはページの残りのデータを解析するために必要です。ページはファイルスペース管理、エクステント管理、トランザクションシステム、データディクショナリ、UNDO、BLOB、そしてもちろんインデックス(テーブルデータ)など、さまざまな用途に割り当てられます。
- The space ID is stored in the header.
- スペースIDはヘッダに格納されます。
- The page number is stored in the header once the page has been initialized. Checking that the page number read from that field matches what it should be based on the offset into the file is helpful to indicate that reading is correct, and this field being initialized indicates that the page has been initialized.
- ページ番号は、ページが初期化された後にヘッダに格納されます。このフィールドから読み取ったページ番号が、ファイル内のオフセットから計算されるべき値と一致しているかを確認することで、正しく読み込めているかどうかをチェックできます。また、このフィールドが初期化されていることは、ページが初期化済みであることを示します。
- A 32-bit checksum is stored in the header, and an older format (and broken) 32-bit checksum is stored in the trailer. The older checksum could be deprecated and that space reclaimed at some point.
- 32ビットのチェックサムがヘッダに格納され、古い形式(かつ壊れていることもある)32ビットチェックサムがトレーラに格納されます。古いチェックサムは将来的に廃止され、その領域を再利用できる可能性があります。
- Pointers to the logical previous and next page for this page type are stored in the header. This allows doubly-linked lists of pages to be built, and this is used for INDEX pages to link all pages at the same level, which allows for e.g. full index scans to be efficient. Many page types do not use these fields.
- このページタイプにおける論理的な前のページと次のページへのポインタがヘッダに格納されます。これにより、ページの双方向リンクリストを構築でき、たとえばインデックスページで同じレベルのすべてのページをリンクして効率的なインデックススキャンが可能になります。ただし、多くのページタイプではこれらのフィールドは使用されません。
- The 64-bit log sequence number (LSN) of the last modification of the page is stored in the header, and the low 32-bits of the same LSN are stored in the trailer.
- ページの最終更新時の64ビットのログシーケンス番号(LSN)がヘッダに格納され、同じLSNの下位32ビットがトレーラに格納されます。
- A 64-bit “flush LSN” field is stored in the header, which is actually only populated for a single page in the entire system, page 0 of space 0. This stores the highest LSN flushed to any page in the entire system (all spaces). This field is a great candidate for re-use in the rest of the space.
- 64ビットの「フラッシュLSN」フィールドがヘッダに格納されますが、実際にはシステム全体でスペース0のページ0にのみ書き込まれます。これはシステム全体(すべてのスペース)でどのページにもフラッシュされた最高のLSNを記録します。このフィールドは、残りのスペースで再利用するのに最適な候補です。
Space files
A space file is just a concatenation of many (up to 232) pages. For more efficient management, pages are grouped into blocks of 1 MiB (64 contiguous pages with the default page size of 16 KiB), and called an “extent”. Many structures then refer only to extents to allocate pages within a space.
スペースファイルは、多数(最大で2の32乗個)のページを単純につなげたものです。
より効率的な管理のため、ページは1MiBのブロック(デフォルトのページサイズ16KiBの場合、連続した64ページ)ごとにグループ化され、これを「エクステント」(extent)と呼びます。
多くの構造体は、スペース内でページを割り当てる際、エクステント単位で参照します。
InnoDB needs to do some bookkeeping to keep track of all of the pages, extents, and the space itself, so a space file has some mandatory super-structure:
InnoDBは、すべてのページやエクステント、そしてスペース自体を管理するためにいくつかの記録作業(ブックキーピング)を行う必要があります。そのため、スペースファイルにはいくつかの必須のスーパー構造(上位構造)が含まれています。

The first page (page 0) in a space is always an FSP_HDR or “file space header” page. The FSP_HDR page contains (confusingly) an FSP header structure, which tracks things like the size of the space and lists of free, fragmented, and full extents. (A more detailed discussion of free space management is reserved for a future post.)
スペース(テーブルスペースなど)の最初のページ(ページ0)は常に「FSP_HDR」ページ、つまり「file space header」ページです。
このFSP_HDRページには「FSPヘッダー」構造体(やや紛らわしいですが)が含まれており、スペースのサイズや、空きエクステント、断片化されたエクステント、完全に埋まったエクステントのリストなどを管理します。
(空き領域管理に関するより詳細な説明は、今後の記事に譲ります。)
An FSP_HDR page only has enough space internally to store bookkeeping information for 256 extents (or 16,384 pages, 256 MiB), so additional space must be reserved every 16,384 pages for bookkeeping information in the form of an XDES page. The structure of XDES and FSP_HDR pages is identical, except that the FSP header structure is zeroed-out in XDES pages. These additional pages are allocated automatically as a space file grows.
FSP_HDRページは、その内部に256エクステント(16,384ページ、256MiB)分の管理情報しか保持するスペースがありません。そのため、16,384ページごとに追加でブックキーピング用の領域をXDESページとして確保する必要があります。
XDESページとFSP_HDRページの構造はほぼ同じですが、XDESページではFSPヘッダー構造体がゼロクリア(無効化)されている点だけが異なります。
これらの追加ページは、スペースファイルが拡張される際に自動的に割り当てられます。
The third page in each space (page 2) will be an INODE page, which is used to store lists related to file segments (groupings of extents plus an array of singly-allocated “fragment” pages). Each INODE page can store 85 INODE entries, and each index requires two INODE entries. (A more detailed discussion of INODE entries and file segments is reserved for a future post.)
各スペースの3番目のページ(ページ2)は「INODEページ」となり、ファイルセグメント(エクステントのグループと、単一で割り当てられた「フラグメント」ページの配列)に関連するリストを格納するために使われます。
各INODEページは85個のINODEエントリーを格納でき、各インデックスには2つのINODEエントリーが必要です。
(INODEエントリーとファイルセグメントに関する詳細な説明は今後の記事に譲ります。)
Alongside each FSP_HDR or XDES page will also be an IBUF_BITMAP page, which is used for bookkeeping information related to insert buffering, and is outside the scope of this post.
FSP_HDRページやXDESページと並んで、IBUF_BITMAPページも存在します。
IBUF_BITMAPページは、インサートバッファリング(insert buffering)に関連する管理情報を記録するために使われますが、この記事の範囲外となります。
The system space
The system space (space 0) is special in InnoDB, and contains quite a few pages allocated at fixed page numbers to store a wide range of information critical to InnoDB’s operation. Since the system space is a space like any other, it has the required FSP_HDR, IBUF_BITMAP, and INODE pages allocated as its first three pages. After that, it is a bit special:
システムスペース(スペース0)はInnoDBにおいて特別な存在であり、InnoDBの動作に不可欠なさまざまな情報を格納するために、多くのページが固定されたページ番号に割り当てられています。
システムスペースも他のスペースと同様に、最初の3ページとして必須の「FSP_HDR」「IBUF_BITMAP」「INODE」ページが割り当てられています。
ただし、それ以降のページ構成は少し特別です:

The following pages are allocated:
- Page 3, type SYS: Headers and bookkeeping information related to insert buffering.
- ページ3(タイプSYS):インサートバッファリングに関連するヘッダーや管理情報が格納されています。
- (補足)インサートバッファリング(Insert Buffering、または変更バッファ/Change Bufferとも呼ばれる)は、InnoDBストレージエンジンがセカンダリインデックス(非ユニークなインデックス)に対する挿入・削除・更新操作を効率化するための仕組み
- ページ3(タイプSYS):インサートバッファリングに関連するヘッダーや管理情報が格納されています。
- Page 4, type INDEX: The root page of the index structure used for insert buffering.
- ページ4(タイプINDEX):インサートバッファリングで使用されるインデックス構造のルートページです。
- Page 5, type TRX_SYS: Information related to the operation of InnoDB’s transaction system, such as the latest transaction ID, MySQL binary log information, and the location of the double write buffer extents.
- ページ5(タイプTRX_SYS):InnoDBのトランザクションシステムの動作に関連する情報が格納されています。例えば最新のトランザクションID、MySQLのバイナリログ情報、ダブルライトバッファのエクステントの位置などです。
- Page 6, type SYS: The first rollback segment page. Additional pages (or whole extents) are allocated as needed to store rollback segment data.
- ページ6(タイプSYS):最初のロールバックセグメントページです。追加のロールバックセグメントデータを格納するために、必要に応じて追加のページ(またはエクステント全体)が割り当てられます。
- Page 7, type SYS: Headers related to the data dictionary, containing root page numbers for the indexes that make up the data dictionary. This information is required to be able to find any other indexes (tables), as their root page numbers are stored in the data dictionary itself.
- ページ7(タイプSYS):データディクショナリに関連するヘッダーが格納されており、データディクショナリを構成するインデックスのルートページ番号が保持されています。この情報は、他のインデックス(テーブル)を探すために必要です。なぜなら、それらのインデックスのルートページ番号はデータディクショナリ自体に格納されているからです。
- Pages 64-127: The first block of 64 pages (an extent) in the double write buffer. The double write buffer is used as part of InnoDB’s recovery mechanism.
- ページ64~127:ダブルライトバッファの最初のブロック(64ページ分=1エクステント)です。ダブルライトバッファは、InnoDBのリカバリ機構の一部として使用されます。
- Pages 128-191: The second block of the double write buffer.
- ページ128~191:ダブルライトバッファの2つ目のブロックです。
All other pages are allocated on an as-needed basis to indexes, rollback segments, undo logs, etc.
それ以外のページは、インデックスやロールバックセグメント、アンドゥログなど、必要に応じて割り当てられます。
Per-table space files
InnoDB offers a “file per table” mode, which will create a file (which as explained above is actually a space) for each MySQL table created. A better name for this feature may be “space per table” rather than “file per table”. The .ibd file created for each table has the typical space file structure:
InnoDBは「file per table(テーブルごとにファイル)」モードを提供しており、作成される各MySQLテーブルに対して1つのファイル(実際には、前述の通り「スペース」です)を作成します。
この機能は「file per table(テーブルごとにファイル)」という名前よりも、「space per table(テーブルごとにスペース)」と呼ぶ方がより正確かもしれません。
各テーブルに対して作成される.ibdファイルは、通常のスペースファイル構造を持っています。

Ignoring “fast index creation” which adds indexes at runtime, after the requisite 3 initial pages, the next pages allocated in the space will be the root pages of each index in the table, in the order they were defined in the table creation. Page 3 will be the root of the clustered index, Page 4 will be the root of the first secondary key, etc.
「fast index creation(高速インデックス作成)」を除くと(これは実行時にインデックスを追加する機能です)、必要な最初の3ページ(FSP_HDR、IBUF_BITMAP、INODEページ)の後に、スペース内で割り当てられる次のページは、テーブル作成時に定義された順番で、各インデックスのルートページになります。
たとえば、ページ3がクラスタインデックスのルートページ、ページ4が最初のセカンダリキーのルートページ、といった具合です。
Since most of InnoDB’s bookkeeping structures are stored in the system space, most pages allocated in a per-table space will be of type INDEX and store table data.
InnoDBの管理情報のほとんどはシステムスペースに格納されているため、テーブルごとのスペース(=.ibdファイル)に割り当てられるページの多くは、INDEXタイプとなり、テーブルのデータを格納します
What’s next?
Next we’ll look at free space management within InnoDB: eaxtent descriptors, file segments (inodes), and lists.
次に、InnoDBにおける空き領域管理について見ていきます。具体的には、エクステントディスクリプタ(extent descriptors)、ファイルセグメント(inodes)、およびリストについて説明します。
コメント