Материалы / Технические статьи / Чекап последовательностей PostgreSQL
Статья

Чекап последовательностей PostgreSQL

Как проверить рассинхронизацию sequence с данными таблицы, приближение к пределу типа и безопасно спланировать исправление.

Продолжаем готовиться к праздникам.

Проверка последовательностей состоит из двух частей: сначала находим sequence, принадлежащие столбцам таблиц, затем для подозрительных пар отдельно сверяем состояние генератора и данные.

1. Найти пары «таблица — столбец — sequence»

SELECT
table_ns.nspname AS table_schema,
table_class.relname AS table_name,
attr.attname AS column_name,
seq_ns.nspname AS sequence_schema,
seq_class.relname AS sequence_name,
sequences.data_type,
sequences.start_value,
sequences.min_value,
sequences.max_value,
sequences.increment_by,
sequences.cycle,
sequences.last_value
FROM pg_class AS seq_class
JOIN pg_namespace AS seq_ns
ON seq_ns.oid = seq_class.relnamespace
JOIN pg_depend AS dep
ON dep.classid = 'pg_class'::regclass
AND dep.objid = seq_class.oid
AND dep.deptype IN ('a', 'i')
JOIN pg_class AS table_class
ON table_class.oid = dep.refobjid
JOIN pg_namespace AS table_ns
ON table_ns.oid = table_class.relnamespace
JOIN pg_attribute AS attr
ON attr.attrelid = table_class.oid
AND attr.attnum = dep.refobjsubid
LEFT JOIN pg_sequences AS sequences
ON sequences.schemaname = seq_ns.nspname
AND sequences.sequencename = seq_class.relname
WHERE seq_class.relkind = 'S'
ORDER BY table_schema, table_name, column_name;

last_value в pg_sequences может быть NULL, если у текущей роли нет прав или sequence ещё не читалась. Standalone-последовательности в этом отчёте намеренно отсутствуют: у них нет зависимости от столбца, и их назначение нужно определять отдельно.

2. Проверить подозрительную пару

Для каждой важной пары сначала посмотрите состояние sequence и только затем max(id):

SELECT last_value, is_called
FROM schema_name.sequence_name;
SELECT max(id) AS max_id
FROM schema_name.table_name;

На индексированном идентификаторе max(id) обычно может использовать край индекса, но план всё равно нужно проверить, особенно на партиционированной таблице. Учитывайте increment_by, min_value, max_value, cycle, cache и тип самого столбца.

Как читать отчет?

Если следующий выдаваемый номер может пересечься с уже существующим id, исправление выполняют в окне без конкурентных вставок. Для обычной возрастающей sequence с шагом 1 шаблон выглядит так:

WITH bounds AS (
SELECT max(id) AS max_id
FROM schema_name.table_name
)
SELECT setval(
'schema_name.sequence_name'::regclass,
COALESCE(max_id, 1),
max_id IS NOT NULL
)
FROM bounds;

Значение 1 здесь допустимо только для sequence с соответствующим минимумом и шагом. Для нестандартной конфигурации формулу нужно изменить. После setval выполните тестовую вставку в транзакции и убедитесь, что все писатели используют именно эту sequence.

На что реагировать

  • Рассинхронизация: следующий номер sequence пересекается с уже занятым диапазоном таблицы.
  • Предел sequence: last_value приближается к max_value с учётом направления и шага.
  • Предел столбца: генератор ещё может расти, но тип integer столбца уже близок к пределу.
  • CYCLE: после границы sequence начнёт повторять диапазон, что особенно опасно для уникального ключа.

На физической реплике диагностические значения могут отличаться от primary; исправляйте генератор только там, где выполняются записи. Для шардированных и распределённых схем нужен отдельный анализ диапазонов идентификаторов.