LoginSignup
5
6

More than 5 years have passed since last update.

railsで複合主キーをやめるmigration

Last updated at Posted at 2019-03-23

概要

railsのシステムでは複合主キーは認められてません。全てテーブルがidという自動採番の主キーを持つのが決まりです。

それはわかっていたのですが、多対多の中間テーブル、例えば、モデルで言えば下記ようなものです。

class User < ApplicationRecord
  has_many :user_skills
  has_many :skills, inverse_of: :users, through: :user_skills
end

class Skill < ApplicationRecord
  has_many :user_skills
  has_many :users, inverse_of: :skills, through: :user_skills
end

# これが私のいうところの中間テーブルです。
class UserSkill < ApplicationRecord
  belongs_to :skill
  belongs_to :user
end

これだけは自分の経験上納得がいかないというか、先入観も大きかったと思いますが、下記の理由で複合主キーを使っていました。

  • 必要のないIDの分の無駄な容量が増える
  • 頻繁にすげ替えが行われるとIDが枯渇するんじゃないか?

ただ、複合主キーで運用してみていくつかの問題がわかっています。

  • UserSkillをレシーバーにして削除ができない。
  • UserSkillをレシーバーにして更新ができない。
  • UserSkillをeager_loadできない。

他にもあるかもしれませんが、今の所私が把握してるのは上記です。

最近は容量に関して言えばストレージもだいぶ低価格になってきてるし、アクセス速度の早いストレージも低価格になってきてます。IDの枯渇に関してはbigintであれば一般的なシステムでは多分問題にならないので、気にしなくてもいいかもと思うようになってきました。

こういうGemもあるのですが、いつまでメンテナンスされるかわからないし、深いところに手を入れてるのでメンテナンスが止まったとき自分でどうにかするコストがかかりそうだと思いました。

そこでRailsの恩恵を受けた方がいいと思うテーブルに関しては複合主キーをやめてみようと思い、そのmigarationを書いてみました。

class UserSkillToSinglePKey < ActiveRecord::Migration[5.2]
  def change
    remove_foreign_key :user_skill, :skill
    remove_foreign_key :user_skill, :user
    reversible do |change|
      change.up do
        execute 'ALTER TABLE user_skill DROP PRIMARY KEY'
      end

      change.down do
        execute 'ALTER TABLE user_skill ADD PRIMARY KEY (skill_id, user_id)'
      end
    end
    add_column :user_skill, :id, :primary_key, unsigned: true, first: true
    add_foreign_key :user_skill, :skill
    add_foreign_key :user_skill, :user
  end
end

ポイントとしては生SQLのところでreversibleを使ってる点、foreign_keyを外さないと主キーをDROPできないことと、add_column :user_skill, :id, :primary_keyとすると、勝手にAUTOINCREMENTになるところくらいですかね。

もし、運用しているサービスにやるのであれば、テーブルロックがかかるのでレコード数によっては問題になるかもしれません。また、一度外部制約を外すので不整合が起きる可能性があるとは思いますのでその点のも考慮に入れてください。

5
6
0

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
5
6