17090


Railsでインデックスを作成しないで、カラムへ複合ユニーク制約を追加する方法を探しています。

環境  
Rails 4.2.3  
Ruby 2.2.2

下記のようなマイグレーションファイルがあるとして

[code]

    class CreateStars < ActiveRecord::Migration
      def change
        create_table :stars do |t|
          t.integer :user_id
          t.integer :comment_id
    
          t.timestamps null: false
        end
      end
    end
    
[/code]

user_idとcomment_idのセットで同じものが記録されないためにはindexを利用して下記のようにユニーク制約をつけるようです。

[code]

    add_index :stars, [:user_id, :comment_id], :unique => true
    
[/code]

しかし、インデックスをつけないで複合ユニーク制約をつける方法は見つけることができませんでした。  
どなたかインデックスをつけないで複合ユニーク制約をつける方法を知っていましたら教えてください。


CC BY-SA 3.0
2015-09-30T04:36:38.797
17087
2015-09-30T09:50:08.773
12232
question
ruby-on-rails
Rails indexを作らないカラムへの複合ユニーク制約の追加方法


以下のように `validates_uniqueness_of`
を使うことで、アプリケーションで複合一意制約を付けることができます。(ただし、DB側で整合性がとれないという事態を避けるため、複合インデックスを作っておく方が良いと思います。)

[code]

    class Star < ActiveRecord::Base
      validates_uniqueness_of :user_id, :scope => [:comment_id]
    end
    
[/code]

なお、`ALTER TABLE ... ADD INDEX ...`
で複合一意制約を追加することが出来ますが、この操作により自動的に複合インデックスが作られます。


CC BY-SA 3.0
2015-09-30T05:32:55.247
17090
2015-09-30T05:32:55.247
76
17087
answer


たいていのRDBMSは、一意制約を実現するのにインデックスを利用しています。したがって、(暗黙か明示かはともかく)一意制約を設定するにはインデックスが必ず作成されます。というわけで「インデックス無しに一意制約を設定する」ことはできません。

どうしてもと言う場合は、何らかの方法(アプリケーション側の実装、など)で一意制約を「エミュレート」するしかありません。

ただし、RDBMSがなぜ一意制約にインデックスを利用するか考えてみると、挿入、更新時に前レコードに対して同一データが存在しないかどうかを確認するにはインデックスを利用するのが一番効率的だからです。したがって、インデックスを作成しないで一意制約を実現するというのは明らかに非効率な方法になります。

また、ロックやトランザクションを慎重に扱わないと、厳密な一意制約は実現できませんし、それは性能にも響いてきます。

(一般的な利用環境を想定すれば)この点からも「インデックス無しに一意制約を実現する」ことは無意味です。


CC BY-SA 3.0
2015-09-30T09:50:08.773
17100
2015-09-30T09:50:08.773
5793
17087
answer