Databases 22 min read

Inside InnoDB: How MySQL Stores Data, Row Formats, Pages, and Indexes

This article explains MySQL's InnoDB storage engine, covering where data files are kept, the different row formats (compact, redundant, dynamic, compressed), the internal 16 KB page layout, record header fields, overflow handling, and how B‑Tree indexes (clustered and secondary) are built and accessed.

dbaplus Community
dbaplus Community
dbaplus Community
Inside InnoDB: How MySQL Stores Data, Row Formats, Pages, and Indexes

Introduction

MySQL stores all table data on disk, but the exact file layout is defined by the storage engine. InnoDB is the default engine and the focus of this article.

InnoDB Row Formats

Each row can be stored in one of four formats: compact , redundant , dynamic , and compressed . The format determines how variable‑length columns, NULL values, and overflow data are recorded.

Compact (default since MySQL 5.7) stores a list of variable‑length field sizes and a NULL‑value bitmap.

Redundant (used before MySQL 5.0) is an older format without those lists; it is rarely seen today.

Dynamic is similar to compact but stores only a 20‑byte pointer for overflow columns.

Compressed builds on dynamic and compresses overflow pages with zlib, trading speed for space.

CREATE TABLE my_table (
  id INT PRIMARY KEY,
  a1 INT,
  a2 INT,
  txt VARCHAR(100)
) ENGINE=InnoDB ROW_FORMAT=COMPACT;

To change the format of an existing table:

ALTER TABLE my_table ROW_FORMAT=DYNAMIC;
SHOW TABLE STATUS LIKE 'my_table';

Record Header Information

Beyond the user columns, each record stores additional metadata:

delete_mask – marks a record as deleted; deleted records form a reusable‑space chain.

min_rec_mask – indicates whether the record is the smallest in a B+Tree node (always 0 for normal records).

n_owned – the number of records owned by the last record of a group; used for page‑directory grouping.

heap_no – the position of the record within the page (0 and 1 are the infimum and supremum pseudo‑records).

record_type – 0 = ordinary, 1 = B+Tree non‑leaf, 2 = infimum, 3 = supremum.

next_record – byte offset from the current record to the next record in the same group.

Row Overflow

If a column exceeds 768 bytes, only the first 768 bytes are stored in the record; the remaining data is placed on separate overflow pages. In the compact format a 20‑byte pointer to those pages is stored, while the dynamic format stores the pointer directly in the record.

InnoDB Data Page Structure

Each InnoDB page is 16 KB and consists of several parts:

File Header (38 bytes) – common information for all page types (page number, previous/next page links).

Page Header (56 bytes) – page‑type‑specific data.

Infimum and Supremum – two pseudo‑records that bound the real user records.

User Records – the actual table rows.

Free Space – unused area that can be reclaimed for new records.

Page Directory – an index of the last record of each group, enabling binary search.

File Trailer (8 bytes) – checksum for page integrity.

InnoDB page layout diagram
InnoDB page layout diagram

Page Directory and Record Search

Records are grouped; the last record of each group stores n_owned. The page directory holds the offset of each group’s last record. To locate a row by primary key:

Perform a binary search on the page directory to find the group that may contain the key.

Traverse the linked list of records inside the group using next_record until the target key is found.

If the key is not in the current page, the B+Tree index moves to the next page via the double‑linked list of pages.

B+Tree Indexing

InnoDB automatically creates a clustered index on the primary key. The leaf nodes of this B+Tree contain the full row data, so the index is the data itself. Secondary indexes store only the indexed column(s) plus the primary key value; they are also B+Trees whose leaf nodes point to the clustered index pages.

B+Tree index structure
B+Tree index structure

Index Costs

Each index adds a separate B+Tree, consuming additional 16 KB pages (space cost). Every INSERT, UPDATE, or DELETE must also modify all affected indexes, causing page splits, record moves, and extra I/O (time cost).

Conclusion

By dissecting InnoDB’s storage logic—row formats, page layout, record headers, overflow handling, and index structures—developers gain a clear view of how MySQL stores and retrieves data, enabling more efficient schema design and query optimization.

Author and source information
Author and source information
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

IndexingMySQLDatabase Storagerow formatData PageB+Tree
dbaplus Community
Written by

dbaplus Community

Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.