🙅‍♂️

PostgreSQLのシーケンスがスキップするタイミング

2023/07/26に公開

PostgreSQLのシーケンスがスキップする

PostgreSQLにて、
シーケンスをとあるテーブルのPK値に用いています。

ある時、このシーケンスがスキップしていることに気づきました。
しかも1度や2度ではありません。
また、このスキップ数は一定であり毎回33増加してました。
シーケンスの増分値には1を設定していたため、詳しく調べることにしました。

原因

シーケンスは取得時のコストを削減するためにある程度の値を前もってキャッシュしています。
そのため、シーケンス取得後にDBの強制終了が発生するとキャッシュが失われ、再取得時にはキャッシュした分をスキップした値が取得されます。

シーケンス取得

select nextval('test_seq');

|result|
|     1|

~~~~~~~~~~~~~~~~~~~~
PostgreSQLを強制終了
~~~~~~~~~~~~~~~~~~~~

再起動後にシーケンス取得

select nextval('test_seq');

|result|
|    34|

シーケンスが33増加していることを確認できました。

その他の原因

AuroraPostgreSQLの場合

AWSのAuroraPostgreSQLを使用している場合、
強制終了以外にもシーケンスのスキップを起こすことができます。

AuroraPostgreSQLはシーケンスのキャッシュをバッファキャッシュに保持しており、
使用頻度の低いシーケンスの場合、キャッシュから弾き出されることでスキップが発生します。

参考:Aurora Postgres Sequences Skipping Values
https://repost.aws/it/questions/QUHhfJbM1TSNKPWDn4jIUgDw

複数セッションでの場合

複数セッションでシーケンスを取得する場合にもスキップは発生します。
これはセッション毎にシーケンスのキャッシュを生成するためです。

参考:PostgreSQL の SEQUENCE キャッシュ動作
https://aws.amazon.com/jp/blogs/news/how-to-solve-some-common-challenges-faced-while-migrating-from-oracle-to-postgresql/

結論

前提として、PostgreSQLのシーケンスは連番を保証していません。
そのため、数値が歯抜けになるのがNGであるのであればシーケンスを採用するべきではないと思いました。

Discussion