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 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 OKR'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.