【実務・中級編】 シーケンス (Sequence) – PostgreSQL

PostgreSQLの「シーケンス」を正しく理解する:自動採番の裏側と現場の勘所

こんにちは。日々のデータベース運用、お疲れ様です。

PostgreSQLを触り始めて最初に覚えることの一つが「自動採番」ですよね。`SERIAL` 型や最近のスタンダードである `GENERATED ALWAYS AS IDENTITY` を使って、IDをポコポコ自動生成している人は多いはず。

でも、ふと「これって裏側でどうやって番号を作ってるんだ?」と疑問に思ったことはありませんか? 今回は、そんなPostgreSQLの縁の下の力持ち、「シーケンス(Sequence)」という仕組みについて、現場の視点から掘り下げて解説します。

—

シーケンスって結局なに?

一言で言えば、「独立した連番生成マシーン」です。

テーブルの一部として存在するのではなく、データベースの中に「独立したオブジェクト」として存在しています。`nextval()`という関数を呼ぶと、「今の値」を返して、内部のカウンターを一つ進める。この単純で強力な仕組みが、PostgreSQLのID発行を支えています。

`SERIAL` vs `IDENTITY`:どっちを使うべき?

現場でよく議論になるのがこれです。結論から言うと、迷わず `IDENTITY` 列を使ってください。

かつては `SERIAL` が主流でしたが、あれは「テーブルとシーケンスを強引に紐付けている」という少し強引な実装なんです。一方で、SQL標準の `GENERATED ALWAYS AS IDENTITY` は、DBエンジンがより適切にライフサイクルを管理してくれる現代的な書き方です。

— 現代の推奨スタイル
CREATE TABLE users (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL
);

こう書くだけで、PostgreSQLは裏で自動的にシーケンスを作成し、`INSERT`のたびに適切に値をセットしてくれます。楽でしょう?

—

実務でハマりがちな「シーケンスの罠」

シーケンスは単純な仕組みですが、大規模な運用になると時々トラブルの種になります。特に注意すべきポイントを2つ共有しておきますね。

1. トランザクションとシーケンスの「巻き戻らない」性質

これが一番の罠です。シーケンスはトランザクションの影響を受けません。

どういうことか?
もしトランザクション内で `nextval()` を呼び出して ID を取得し、その後の処理で `ROLLBACK` したとしても、一度進んだシーケンスの値は元に戻りません。

「IDが10、11と続いて、急に13になった!」という現象はバグではなく仕様です。途中でエラーが起きてロールバックした分は「欠番」として消費されてしまう。IDに「連番であること」というビジネス的な厳密さを求めてはいけない、という鉄則はここから来ています。

2. シーケンスの値とデータがズレる(同期ズレ)

たまに、手動で `INSERT` 文を書くときに `id` を指定してしまったり、データの移行作業でシーケンスの現在値とテーブルの最大値がズレてしまうことがあります。

そんな時は焦らず、`setval` 関数で修正しましょう。

— 現在の最大値を確認
SELECT MAX(id) FROM users;

— シーケンスを最新のIDに合わせる(例: 次回発行値が501になるように設定)
SELECT setval(pg_get_serial_sequence(‘users’, ‘id’), 500);

`pg_get_serial_sequence` を使えば、テーブル名からシーケンス名をわざわざ調べなくても、動的に紐付いているシーケンスを特定してくれます。これ、覚えておくとトラブル対応の時にめちゃくちゃ速いです。

—

シーケンスを使いこなすためのアドバイス

シーケンスは、単にIDを振るだけでなく、「並行処理」の観点でも非常に優秀です。

多くのプロセスが同時に `INSERT` しても、PostgreSQLのシーケンスはロックを最小限にして高速に番号を払い出すように設計されています。自前で「最大値を取得して+1する」なんて実装をアプリ側で書こうとすると、デッドロックの嵐に巻き込まれます。データベースの機能を信じて、シーケンスに任せるのが一番の最適解です。

まとめ

  • シーケンスは「独立した番号生成オブジェクト」である。
  • `SERIAL` より `IDENTITY`。現代のベストプラクティスに従おう。
  • 「欠番」は仕様。IDは連番であることではなく、一意であることに価値がある。
  • 困った時の `setval` と `pg_get_serial_sequence`。これだけは頭の片隅に置いておこう。

データベースの裏側にある「当たり前の仕組み」を少し理解するだけで、トラブルに遭遇した時の余裕が変わってきます。「なぜそう動くのか」を意識する姿勢、これからも大切にしてくださいね。

また現場で気になることがあれば、いつでも聞いてください。それでは、良いDBライフを!

コメント

タイトルとURLをコピーしました