【问题标题】:How to optimize querying for thousands of IDs如何优化对数千个 ID 的查询
【发布时间】:2013-05-01 18:31:50
【问题描述】:

以下是三个连续查询及其基准性能:

ids = @Company.projects.submitted.uniq.collect(&:person_id)
  1.370000   0.060000   1.430000 (  3.763946)

@persons = Person.where("id IN (?)", ids)
  0.030000   0.000000   0.030000 (  0.332878)

@emails = @persons.collect(&:email).reject(&:blank?)
  16.550000  1.640000  18.190000  (128.002465)

ids 包含近 10000 个 id,在运行我看到的最后一个查询时:

SELECT "persons".* FROM "persons" WHERE (id in (121,142,173,178...14202))
(*1000s ->) User Load (13.0ms)  SELECT "users".* FROM "users" WHERE "users"."roleable_type" = 'Person' AND "users"."roleable_id" = 121 LIMIT 1

Indexes on User:
add_index "users", ["roleable_id", "roleable_type"], :name => "index_users_on_roleable_id_and_roleable_type"
add_index "users", ["roleable_type", "roleable_id"], :name => "index_users_on_roleable_type_and_roleable_id"

如何解决这里发生的问题?

【问题讨论】:

    标签: ruby-on-rails postgresql activerecord query-optimization rails-activerecord


    【解决方案1】:

    您拥有的第二个查询实际上并没有访问数据库。它正在构建一个 ActiveRecord::Relation (一个惰性查询),直到调用第三个查询才被触发。您可以通过在第二个查询的末尾添加 .all 来证明这一点。

    要解决性能问题,您希望使用文字列表摆脱 IN (),因为这确实会损害大型列表的数据库性能:

    @persons = Person.joins(:projects).merge(@Company.projects.submitted)
    

    您也可以使用子查询来执行此操作(尽管效率低于 JOIN):

    subquery = @Company.projects.submitted.select("projects.person_id").to_sql
    @persons = Person.where("id IN (#{subquery})")
    

    如果您只想获得生成的 @emails,而不真的需要 @persons 集合,您可以像这样稍微提高效率:

    @email = Person.joins(:projects).merge(@Company.projects.submitted).
                      where("LENGTH(persons.email) > 0").pluck(:email)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-27
      • 2018-10-29
      • 2021-10-22
      • 2012-04-30
      • 2012-11-17
      • 1970-01-01
      • 2012-12-22
      相关资源
      最近更新 更多