InnoDB and the clustered primary key

MySQL · Essentials · 12 min

Understanding the clustered index explains most InnoDB performance advice about keys and secondary indexes.

MySQL supports pluggable storage engines; InnoDB is the default and the one to use. It provides transactions, row-level locking, foreign keys, MVCC and crash recovery. (MyISAM, the old default, has none of these and should not be used for application data.)

The most important InnoDB fact: every table is a B-tree index on its primary key — a clustered index. Rows are stored in the leaf pages of that tree, in primary-key order. Consequences:

  • Lookups and range scans by primary key are very fast; they find the row directly.
  • Secondary indexes store the indexed columns plus the primary key value, not a row pointer. A lookup through a secondary index finds the PK, then searches the clustered index again. A wide primary key (say a 36-character UUID string) is therefore copied into every secondary index.
  • Inserting in increasing PK order (AUTO_INCREMENT) appends to the end of the tree. Random keys like UUIDv4 cause page splits and a bigger working set; if you need UUIDs, store them as BINARY(16) and prefer time-ordered ones (UUID_TO_BIN(UUID(), 1) reorders MySQL's time-based UUID for this).
  • If you don't define a primary key, InnoDB uses the first NOT NULL unique key or adds a hidden 6-byte row id. Always declare one explicitly.

Each table lives in its own .ibd file by default (innodb_file_per_table).

Example

CREATE TABLE orders (
    id          BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,   -- clustered index
    customer_id BIGINT UNSIGNED NOT NULL,
    status      VARCHAR(20) NOT NULL,
    created_at  DATETIME NOT NULL,
    KEY idx_customer (customer_id)   -- leaf entries: (customer_id, id)
) ENGINE = InnoDB;

-- uses idx_customer only: the PK is already inside the secondary index
EXPLAIN SELECT id FROM orders WHERE customer_id = 7;
-- type: ref  key: idx_customer  Extra: Using index

SELECT engine, COUNT(*) FROM information_schema.tables
WHERE table_schema = DATABASE() GROUP BY engine;   -- InnoDB | 1

Remember

  • InnoDB tables are clustered on the primary key
  • Secondary indexes contain the primary key, so keep the PK narrow
  • Sequential primary keys insert efficiently; always declare one

Watch out for

  • Using a CHAR(36) UUID string as the primary key of a large table with many secondary indexes.

Check yourself

  1. What does an InnoDB secondary index entry point to?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: dev.mysql.com/doc/refman/8.4/en/innodb-index-types.html