Guide · Reading
What a sequence page tells you
Open a sequence page when an insert fails with a duplicate key on an id column, when a table's id is integer and the numbers look big, or before you reset or drop one. If every id in your schema is bigint and nothing is failing, skip this one.
The symptom
An insert into billing.events fails with duplicate key value violates unique constraint "events_pkey", the day after a restore. Or nothing has failed yet, and you notice that events.id is integer and the latest id is past 1.5 billion.
The sequence page of billing.events_id_seq, a bigint sequence feeding the integer column billing.events.id, 71% of the way to the integer limit.
What a sequence is
A sequence is a counter that lives outside your transaction. nextval() hands over the next number at once, before the INSERT that asked for it commits, and that number is spent whether the insert commits, fails or rolls back. That is why id columns have gaps, and why gaps are fine.
The header reads Serial · feeds events.id integer · 1.5B handed out. The sections below are Pro. On Free the header keeps Serial, the table and the engine, and the page stops after Definition with the Pro sections named over a blurred silhouette (Object pages shows the gate). The verdict at the top: About 5 months left. events_id_seq has used 71.4% of the values up to the integer limit of events.id. Widening to bigint rewrites the table, so plan it ahead., with Open the widening SQL beside it.
How much is left
The sequence is bigint and could count to 9.2 quintillion. The column it feeds is integer and stops at 2,147,483,647. The gauge is drawn to the column's limit, with a dashed extension for the sequence's own, because the column is what runs out. The marker sits at 1,533,422,880, 71.4%.
Values per day is measured from occurred_at on events over the last 30 days. At 4M values a day the remaining 614 million last about five months, and until then nothing in any log says so.
Latest values
The left column is the highest eight values of events.id, with the sequence's next value placed among them. The right column says which of two states you are in.
In step with the table: the next value, 1,533,422,881, is past the highest id in events, so the next insert is safe.
Behind the table: the table already holds the value the sequence would hand out next, so inserts fail with a duplicate key until it moves past the table. This happens after a restore or a bulk import that inserted explicit ids. Open setval in a console opens the fix:
-- Moves events_id_seq so its next value follows the highest id in events.
SELECT setval('billing.events_id_seq', (SELECT max(id) FROM billing.events), true);
This sequence has CACHE 1. With CACHE 20 each connection reserves 20 values at a time, which is cheaper on a busy sequence, and loses the unused ones when it closes, so gaps of up to 20 are normal.
Widening events.id to bigint
This section appears only at warn or critical. Its lead sentence is the cost: a bigint column never runs out, and changing the type rewrites every table below, each locked for reads and writes until its rewrite finishes, about 322 GB in total.
The table lists every column that changes: events.id itself, integer → bigint, 310 GB, then every foreign key column that points at it and is still integer. Open in console opens the ALTER TABLE … ALTER COLUMN … TYPE bigint statements in one transaction.
That ALTER holds an ACCESS EXCLUSIVE lock for the whole rewrite, and on 310 GB that is hours. The five months of runway are for the alternative the page names under the button: add a bigint column, backfill it in batches, then swap it in.
Who takes values from it
billing.events.id, serial column · integer · unique · partitioned table, then billing.invoice_events and billing.event_attachments, whose columns take values from the same sequence. A column's default calls nextval(), and inserts may also set id themselves, which is how a table gets ahead of its sequence. An identity column declared GENERATED ALWAYS closes that door.
Who can use it
A table of roles against Take next, Read and Reset, which are nextval(), currval() and setval(). Here app can do all three, app_rw can take and read, and reporting can only read. A PUBLIC row is highlighted, because then every role can take values. All properties and DDL fold out below.
MySQL, MariaDB and SQLite
- MySQL and MariaDB: an
AUTO_INCREMENTcolumn is the counter, andAll propertiesshowsNext value,auto_increment_incrementandinnodb_autoinc_lock_mode. - SQLite: an
INTEGER PRIMARY KEYis the rowid, and the property isLargest id in the table, orLargest id handed out (sqlite_sequence)withAUTOINCREMENT. Ids are 64-bit, so there is no runway to watch.
Caveats
- The runway is a straight line through the last 30 days. A launch or a backfill changes it. Without a timestamp column the rate comes from insert counts since the statistics reset.
- A sequence with
CYCLEon a unique column gets its own warning: at the limit it starts again from 1, and those values are taken. - The sizes here come from the 12-million-row copy of the sample.