0

私のアプリはPostgreSQLデータベースを使用しています。次のような移行があります。

class CreateTagAssignments < ActiveRecord::Migration
  def change
    create_table :tag_assignments do |t|
      t.integer :tag_id
      t.integer :quote_id
      t.integer :user_id

      t.timestamps
    end

    add_index :tag_assignments, :tag_id
    add_index :tag_assignments, :quote_id
  end
end

レコードはこれらの2つの列で頻繁に検索されるため、それぞれに個別のインデックスを作成します。しかし、ここで、データベースレベルでペア( tag_id、 )の一意性を強制したいと思います。quote_id試しadd_index :tag_assignments, [:tag_id, :quote_id], unique: trueましたが、エラーが発生しました:

PG::Error: ERROR:  could not create unique index "index_tag_assignments_on_tag_id_and_quote_id"
DETAIL:  Key (tag_id, quote_id)=(10, 1) is duplicated.
: CREATE UNIQUE INDEX "index_tag_assignments_on_tag_id_and_quote_id" ON "tag_assignments" ("tag_id", "quote_id")

では、複数のインデックスが複数列のインデックスの役割を果たしているように見えますか?もしそうなら、私はで制約を追加することがALTER TABLE ... ADD CONSTRAINTできますが、ActiveRecordでそれを行うにはどうすればよいですか?

編集:手動で実行ALTER TABLE ... ADD CONSTRAINTすると同じエラーが発生します。

4

2 に答える 2

4

アーウィンが指摘しているように、「キー(tag_id、quote_id)=(10、1)が重複しています」という制約違反のエラーメッセージは、一意の制約が既存のデータによってすでに違反されていることを示しています。モデルの表示内容から、さまざまなユーザーがそれぞれタグと見積もりの​​間に共通の関連付けを導入できると推測します。そのため、quote_id、tag_idのペアのみの一意性を制限しようとすると、重複が発生します。複合インデックスは、先行キーへのインデックスアクセスに引き続き役立ちます(ただし、複合インデックスのキー密度は低くなるため、単一列インデックスよりも効率がわずかに低下します)。おそらく、必要な速度と、2つのインデックス(一方のIDの単一列インデックスともう一方のIDを先頭フィールドとする3つのIDすべての複合インデックス)を使用した適切な一意性制約を取得できます。

add_index :tag_assignments, :tag_id
add_index :tag_assignments, [:quote_id,:tag_id,:user_id], unique: true

Pg> = 9.2を使用している場合は、9.2のインデックス可視性マップを利用して、カバーするインデックスのインデックスのみのスキャンを有効にすることができます。この場合、上記の最初のインデックスに3つのIDをすべて含め、tag_idとquote_idを先頭にしておくと便利な場合があります。

add_index :tag_assignments, [:tag_id,:quote_id,user_id]

user_idがクエリをどのように制約するかは不明であるため、その位置を以前にプロモートしたインデックスも必要になる場合があります。

于 2012-12-07T00:16:40.987 に答える
2

では、複数のインデックスが複数列のインデックスの役割を果たしているように見えますか?

この結論は真実ではなく、あなたが説明したことの後で根拠がありません。エラーメッセージはその反対を示しています。複数列のインデックスまたはUNIQUE複数の列に対する制約(複数列のインデックスも実装)は、複数の単一列のインデックスからは得られない機能を提供します。

于 2012-12-06T22:27:46.663 に答える