Обидва способи створюють автоінкрементний цілочисельний ключ на основі послідовності (sequence).
serial / bigserial - старий спосіб, по суті скорочення:
id bigserial PRIMARY KEY
-- розгортається в:
-- id bigint NOT NULL DEFAULT nextval('orders_id_seq')
-- + окрема послідовність, «прив'язана» до колонки
Identity (PostgreSQL 10+, стандарт SQL):
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY
-- або
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
Чому identity краще:
- Стандарт SQL - переноситься між СУБД.
- Послідовність - частина колонки: права, видалення таблиці, копіювання структури працюють коректно. З
serialтреба окремо давати права на послідовність, іCREATE TABLE ... (LIKE ...)може поділити послідовність між таблицями. GENERATED ALWAYSзабороняє вставляти власні значення (можна лише явно зOVERRIDING SYSTEM VALUE). Захищає від ручних ID, що потім конфліктують з послідовністю.- Керування через
ALTER TABLE ... ALTER COLUMN id RESTART WITH 1000.
Спільні нюанси:
- Дірки в номерах - норма. Значення з послідовності береться до коміту й не повертається при відкаті. ID 5, 6, 8 - не баг. Для «безперервних» номерів рахунків послідовність не підходить.
bigint, а неint: 2,1 мільярда закінчуються несподівано швидко в таблицях подій і логів, а зміна типу первинного ключа на великій таблиці - болюча операція.- Після ручного імпорту даних з явними ID послідовність треба зсунути:
SELECT setval('orders_id_seq', (SELECT max(id) FROM orders));.
Laravel $table->id() на PostgreSQL створює bigserial-ключ - для більшості застосунків різниця непомітна.