データベースのPRIMARY KEYを自動採番せずにアプリケーション側で生成する

データベースの自動採番

データベースにはPRIMARY KEY(要はID)を自動採番で生成してくれる機能を提供していることが多い。

サロゲートキーのような、特に意味のないデータのIDを発行するときに重宝する。

自動採番のデメリット

しかし、自動採番にはデメリットもある。

IDの発行がRDBMSに依存してしまう

型やSQLも含め、自動採番の機能はRDBMSによって異なることが多いため、アプリケーションのRDBMSへの依存度が高くなってしまう。

DBをまるごと乗せ換えるようなケースはそれほど多くないと思うが、データアクセスのライブラリやフレームワークも含め、バージョン間での互換性は気になるところ。

自動採番されたIDを知るコストがかかる

InsertしたばかりのデータのIDを使い回すケース等で発生しがち。

同一トランザクションで関連テーブルのFKとして登録することはよくあると思う。

ライブラリやフレームワークが解決してくれることも多いが、処理コストは間違いなくかかっているはずだし、場合によっては実装コストもかかってくる。

アプリケーション側で生成するという選択肢

「データベース=データを保存するところ」と考えると、「アプリケーション=データを作るところ」と考えられると思う。

であれば、サロゲートキーのようなものであっても、データの一意性はまず作成側で担保するべきともいえるし、作成側が最初から知っているべき情報ともいえる。

Javaで生成する例

JavaのUUIDを利用して擬似乱数を生成し、それを文字列化してIDにする。

UUID (Java Platform SE 8)

String id = UUID.randomUUID().toString();

UUID#toString() は常に36文字になるため、DB側は CHAR(36) で宣言するとよい。

補足

順序性

IDに順序性が求められる場合もあると思うが、ソートが要件に入っている時点で意味を持っているカラムと考えられる。

IDと順序性は同列に語るものではない気がする。

「ID順」が守るべきソート順は何か?ということなので、たとえば登録順なら登録日時として持つべきだよね、とかそういう話だと思う。

衝突

乱数生成の場合、理論上衝突する可能性がある。

一概にはいえないが、データの整合性を(最終的に)守ることはデータベース側に任せて良いのではないかと思う。

要はDBの制約に頼ろうという話で、エラーハンドリングであったりリトライで解決できるレベルの話ではなかろうか。

頻度にもよるとは思うが、固く行くなら重複チェック処理を混ぜ込むか。
(その場合コストは自動採番と同様になるが、RDBへの依存度は下がる)

参考

stackoverflow.com