Skip to content

The history list: InnoDB's bloat metric ​

For MySQL 8.4 InnoDB, history-list length tracks committed update undo awaiting purge. It is not a byte count, row-version count, or a complete measure of table or undo-file bloat. The purge manual describes history retention under write-heavy workloads and long-running read transactions.

One idle reader, two hundred pinned transactions ​

R creates a REPEATABLE READ view at v=0. A commits 200 single-row updates. The scenario asserts trx_rseg_history_len >= 200 while R still reads zero. It does not assert an exact increase of 200, inspect undo pages, or time the later purge.

R
A
read view opens
200 commits pile up undo
history_len ≥ 200 — pinned
R still sees v=0
COMMIT→ purge can drain it

R opens a read view — and then does nothing.

R> BEGIN;
Query OK

R> SELECT v FROM counters;
 v 
---
 0 
(1 row)

Meanwhile the application hums along: 200 small transactions, each updating one row and committing. Every one of them must keep its undo — R's old read view prevents purge from advancing past the retained history.

A> CALL bump(200); -- 200 committed single-row updates
Query OK

A> SELECT count >= 200 AS pinned_by_reader FROM information_schema.INNODB_METRICS WHERE name = 'trx_rseg_history_len'; -- the history-list counter is at least 200 while R retains its view
 pinned_by_reader 
------------------
                1 
(1 row)

R> SELECT v FROM counters; -- R still reads its original world — that's what all that undo buys
 v 
---
 0 
(1 row)

R> COMMIT;
Query OK

R's commit removes its read-view retention requirement. Background purge and other readers determine later cleanup; this run does not wait for or assert history-list drainage.

Verified against MySQL 8.4.11 · Run it yourself · Scenario source

The PostgreSQL parallel is limited ​

Both engines can retain history behind an old snapshot, but this does not make InnoDB purge and PostgreSQL VACUUM identical. InnoDB maintains undo and also removes delete-marked index records; PostgreSQL manages heap tuple versions.

An old read view can prevent purge of history it may need even when the reader is idle. Growth requires continued production of retained update undo; an open transaction without a read view is not by itself proof of that retention. Not every committed write adds the same history, and ending R only removes its retention requirement. Other readers and purge capacity can still matter.

Monitor the trend of trx_rseg_history_len, also displayed as History list length in SHOW ENGINE INNODB STATUS. Investigate old read views and write load rather than diagnosing a forgotten transaction from this counter alone. The production query uses the same metric. Next: purge.

Further reading ​

The reconstructed support assessment records the exact manual support and execution limits for this lesson.

MIT Licensed · Every transcript on this site was generated by a real database run against MySQL 8.4.11 and PostgreSQL 18.6 at 8fa27b8; shared YAML has an independent psycopg/PyMySQL check.