【问题标题】:Separate indexes on two columns and unique constraint on the pair in RailsRails 中两列的独立索引和对的唯一约束
【发布时间】:2012-11-25 01:38:38
【问题描述】:

我的应用程序使用 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

这两列将非常频繁地搜索记录,因此我希望为每列设置一个单独的索引。但现在我想在数据库级别强制这对(tag_idquote_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 会产生同样的错误。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 postgresql activerecord


    【解决方案1】:

    正如 Erwin 所指出的,“Key (tag_id, quote_id)=(10, 1) is duplicated”约束违规错误消息告诉您,您的唯一约束已被现有数据违反。我从您的模型的可见内容推断出不同的用户可以在标签和报价之间引入一个共同的关联,因此当您尝试仅限制 quote_id,tag_id 对的唯一性时,您会看到重复。复合索引对于前导键的索引访问仍然有用(尽管效率略低于单列索引,因为复合索引的键密度较低)。您可能会获得所需的速度以及具有两个索引的适当唯一约束,其中一个 id 上的单列索引和所有三个 id 上的复合索引,另一个 id 作为其前导字段。如果从标记到引用的映射比从引用到标记的映射更频繁的访问路径,我会试试这个:

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

    如果您使用 Pg >= 9.2,则可以利用 9.2 的索引可见性映射来启用对 covering indexes 的仅索引扫描。在这种情况下,让上面的第一个索引包含所有三个 id 可能会有好处,tag_id 和 quote_id 前导:

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

    尚不清楚 user_id 如何约束您的查询,因此您可能会发现您希望索引的位置也更早提升。

    【讨论】:

    • 哦,谢谢,我误解了消息,我以为索引重复了,忘记检查数据了。再次感谢:)
    【解决方案2】:

    那么多个索引显然可以完成多列索引的工作?

    根据你的描述,这个结论是不真实的,也是没有根据的。错误消息表明相反。多列上的 multicolumn indexUNIQUE 约束(也实现多列索引)提供了您无法从多个单列索引中获得的功能。

    【讨论】:

      猜你喜欢
      • 2010-11-23
      • 2021-11-02
      • 2011-02-24
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      相关资源
      最近更新 更多