LoginSignup
26
25

More than 5 years have passed since last update.

Ruby on RailsでAutoIncrementを使わずにシーケンスidをふる

Last updated at Posted at 2015-08-15

シーケンスのIDを自前でふる

Railsの場合、ActiveRecordを使って、AutoIncrementでidを発行しているのが一般的。
でも、自前でふりたい場合がある!
主な理由は、テーブルやデータベースを跨いで連番のidをふりたい場合などかなと思います。例えばシャーディングとか(Railsでシャーディングをサポートしていないけど)。
将来的に大量のレコードが出来て、構成を変える可能性がある場合にはあらかじめ自前でidをふっておくと良い事があるかもしれません。

テーブル構成

シーケンスidを管理するテーブルと、シーケンスidを使うテーブルを作る。例として、userテーブルにuser_idをふるシステムを考える。

テーブル構造
userテーブルには、user_idとemail、暗号化したパスワードを入れる想定。
user_sequenceにidがどこまで進んだかを記録しておく。
シーケンスの処理は単純なのでトランザクションを考慮しない方がパフォーマンスが出るためMyISAMで。仮にinnodb側がrollbackしても発行されたidが使われないだけなので問題ない。

* user_sequence
CREATE TABLE `user_sequence` (
  `id` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

* user_auths
CREATE TABLE `user_auths` (
  `user_id` int(10) unsigned NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `encrypted_password` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ''
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

モデルと処理

シーケンス管理側

"models/user_sequence.rb"

class UserSequence < ActiveRecord::Base
  self.table_name = :user_sequence
  self.primary_key = :id
end

ユーザーテーブル側

"models/user_auth.rb"

class UserAuth < ActiveRecord::Base
  before_save :set_user_id

  def set_user_id
    if self.user_id.blank?
      ActiveRecord::Base.uncached do
        UserSequence.connection.execute('UPDATE user_sequence SET id = LAST_INSERT_ID(id + 1)')
        user_id = UserSequence.find_by_sql('SELECT SQL_NO_CACHE LAST_INSERT_ID() AS id').first
        self.user_id = user_id['id']
      end
    end
  end
end

以下の動作によりシーケンステーブルに+1した後に、その値をuser_idとして利用している。

  • before_saveのhookでset_user_idを呼び出す

  • シーケンステーブルに今のID+1をINSERT

  • user_idにINSERT後(+1された後の)のLAST_INSERT_ID()を入れる

呼び出し元はどこでも良いので、テーブル間でも一貫性の取れたシーケンスIDをふる事が出来る。

まとめ

Rails的にはそもそもシャーディングしないっぽいのでそこまで必要無いのかなと思いつつも、将来的に非常に大きくなりそうなアプリの設計をしていたのでこんな感じで作ってみました。

26
25
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
25