Ruby on Rails中的多列索引


97

我正在实现跟踪用户阅读过哪些文章的功能。

  create_table "article", :force => true do |t|
    t.string   "title"
    t.text     "content"
  end

到目前为止,这是我的迁移:

create_table :user_views do |t|
  t.integer :user_id
  t.integer :article_id
end

总是会查询user_views表来查找两列,而不会只查找其中一列。我的问题是索引应如何显示。这些表的顺序是否有所不同,是否应该有更多选择或其他选择。我的目标数据库是Postgres。

add_index(:user_views, [:article_id, :user_id])

谢谢。

更新:
因为在两列中只能存在包含相同值的一行(因为要知道user_id是否已读取article_id),我应该考虑:unique选项吗?如果我没有记错的话,那意味着我不必自己进行任何检查,只需在用户每次访问文章时插入一下即可。


“将始终查询user_views表以查找两列,而不是仅查找一列。” -永远不会有“查找此用户已查看的所有文章”或“查找已查看此文章的所有用户”查询?我感到惊讶。
David Aldridge

Answers:


212

顺序对于索引确实很重要。

  1. 将最有选择性的字段放在第一位,即,该字段使行数最快的范围缩小。
  2. 索引仅在从头开始按顺序使用其列的范围内使用。即,如果在上建立索引[:user_id, :article_id],则可以在user_id或上执行快速查询user_id AND article_id,但不能在上执行article_id

您的迁移add_index行应如下所示:

add_index :user_views, [:user_id, :article_id]

有关“独特”选项的问题

在Rails中执行此操作的一种简单方法是validates在模型中使用,范围uniqueness如下(文档):

validates :user, uniqueness: { scope: :article }

7
在索引中,顺序非常重要。将where子句放在左边,并在索引的右边加上顺序列。stackoverflow.com/questions/6098616/dos-and-donts-for-indexes
Denis de Bernardy 2011年

1
请注意validates_uniqueness_of(及其堂兄,validates uniqueness:)很容易出现比赛条件
Ben Aubin

1
如以上注释以及stackoverflow.com/a/1449466/5157706stackoverflow.com/a/22816105/5157706所述,请考虑同时在数据库上添加唯一索引。
Akash Agarwal,

25

只是关于在验证时检查唯一性与在索引上检查唯一性的警告:后者由数据库完成,而引物由模型完成。由于模型可能同时运行多个并发实例,因此验证受竞争条件的影响,这意味着在某些情况下验证可能无法检测到重复项(例如,在同一时间提交两次相同的表单)。


那么哪个更好呢?数据库方面还是validates_uniqueness_of?
WM

9
都。validates_uniqueness_of可用于在应用程序中优雅地显示错误消息,例如在保存表单时。数据库约束将确保您不会以dup记录结尾,即使知道模型中已指定验证。另外,您可以挽救ActiveRecord异常,并向用户显示好消息。
UGIS Ozols

5
@WM如果必须选择一个,请使用数据库约束。即使不同的非RoR应用程序与您的数据进行交互,这也将起作用,并确保长期的一致性。
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.