Чекап последовательностей PostgreSQL
Как проверить рассинхронизацию sequence с данными таблицы, приближение к пределу типа и безопасно спланировать исправление.
PostgreSQLПоследовательностиОбслуживаниеБезопасность данныхПродолжаем готовиться к праздникам.
Проверка последовательностей состоит из двух частей: сначала находим 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_valueFROM pg_class AS seq_classJOIN pg_namespace AS seq_ns ON seq_ns.oid = seq_class.relnamespaceJOIN 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.refobjidJOIN pg_namespace AS table_ns ON table_ns.oid = table_class.relnamespaceJOIN pg_attribute AS attr ON attr.attrelid = table_class.oid AND attr.attnum = dep.refobjsubidLEFT JOIN pg_sequences AS sequences ON sequences.schemaname = seq_ns.nspname AND sequences.sequencename = seq_class.relnameWHERE 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_calledFROM schema_name.sequence_name;
SELECT max(id) AS max_idFROM 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; исправляйте генератор только там, где выполняются записи. Для шардированных и распределённых схем нужен отдельный анализ диапазонов идентификаторов.