【问题标题】:ActiveRecord with Postgres: Has Many Through and Indexing带有 Postgres 的 ActiveRecord:有许多直通和索引
【发布时间】:2012-05-07 21:07:52
【问题描述】:

假设您有三个模型:

class Collection < ActiveRecord::Base
  has_many :comments, through => :users
end

class User < ActiveRecord::Base
  belongs_to :collection
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
end

这样的索引:

add_index :users, :collection_id
add_index :comments, :user_id

如果您有其 cmets 的集合查询:

@collection.comments

它会使用两个索引吗?

编辑:

这会产生一个如下所示的查询:

SELECT "comments".* FROM "comments" INNER JOIN "users" ON "comments"."user_id" = "users"."id" WHERE "users"."collection_id" = 232

使用 EXPLAIN 它声称它仅使用“对用户使用 index_users_on_collection_id 进行索引扫描”

所以大概它从用户的collection_id索引中快速获取用户,然后在加入用户时搜索所有的cmets?如果有很多 cmets(假设有 100,000 个),这个查询会不会执行得不好?

谢谢。

【问题讨论】:

  • 与其对EXPLAIN 的输出进行模糊的描述,为什么不显示呢?更好的是,显示EXPLAIN ANALYZE 输出,这样我们就可以看到预期 行数和成本以及实际 行数和时间。此外,不要期望大型数据集上的计划与小型数据集上的计划相同。
  • 执行计划不是假设性的,它们是根据当前基数和过滤器和连接字段的选择性的估计来制定的。如果您认为使用 100K cmets 的计划会很慢,那么只有当您生成具有 100K cmets 和当前统计数据的计划时才有意义。如果您遇到实际性能问题,请按照@kgrittn 的建议运行并发布explain analyze
  • 通常评论来自一个用户。所以你的数据模型可能不符合要求。可能应该是 n:1 而不是 n:m - 一个表 comment,其外键列引用作者 (user)。
  • 在开发、暂存等任何情况下使用 Rails 插入 100,000 条记录(或更多数量级)并再次运行解释非常容易。

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


【解决方案1】:

您不能依赖小表的 EXPLAIN 计划与大表相同。计划随着桌子大小的变化而变化。

这就是说,如果它最终通过 cmets 进行顺序扫描并且存在大量行,那么您可能需要确保 cmets 表的外键字段上存在索引。如果 PostgreSQL 从磁盘 I/O 的角度评估这将是一个净赢,并且这意味着表足够大,可以从使用索引扫描中受益,并且索引扫描不会检索到很大一部分,那么 PostgreSQL 将使用索引表。

【讨论】:

    猜你喜欢
    • 2014-09-11
    • 2020-01-24
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    • 1970-01-01
    • 2010-10-20
    • 2021-08-03
    相关资源
    最近更新 更多