【问题标题】:Rails - index for a query over a join tableRails - 对连接表的查询的索引
【发布时间】:2012-05-08 12:32:53
【问题描述】:

在我的应用文章中有很多子或父文章通过自引用加入模型article_relationships

class Article < ActiveRecord::Base

  has_many  :parent_child_relationships,
            :class_name   => "ArticleRelationship",
            :foreign_key  => :child_id,
            :dependent    => :destroy
  has_many  :parents,
            :through    => :parent_child_relationships,
            :source     => :parent

  has_many  :child_parent_relationships,
            :class_name   => "ArticleRelationship",
            :foreign_key  => :parent_id,
            :dependent    => :destroy
  has_many  :children,
            :through    => :child_parent_relationships,
            :source     => :child
end

class ArticleRelationship < ActiveRecord::Base
  belongs_to :parent, :class_name => "Article"
  belongs_to :child, :class_name => "Article"
end

我有一个关于 article_relationships 的相当复杂的查询,它深入到文章表中

ArticleRelationship.joins(:parent, :child).where("((articles.type IN (:parent_article_type) AND parent_id IN (:ids)) OR (children_article_relationships.type IN (:child_article_type) AND child_id IN (:ids)) AND (article_relationships.created_at > :date OR article_relationships.updated_at > :date))", {:parent_article_type => "Emotion", :child_article_type => "Gateway", :ids => [1,2,3,4], :date => "2010-01-01"})

有什么方法可以有效地索引它吗?

【问题讨论】:

  • 对于复杂查询,请使用squeel gem。它通过not_inlike_any 和其他很酷的功能扩展了您的语法。值得尝试。 github.com/ernie/squeel

标签: mysql ruby-on-rails indexing


【解决方案1】:

所以,只是为了可读性,

ArticleRelationship.joins(:parent, :child).
 where("((articles.type IN (:parent_article_type) AND parent_id IN (:ids)) OR
         (children_article_relationships.type IN (:child_article_type) AND child_id IN (:ids))
        AND (article_relationships.created_at > :date OR article_relationships.updated_at > :date))",
       { :parent_article_type => "Emotion",
         :child_article_type => "Gateway",
         :ids => [1,2,3,4], :date => "2010-01-01" })

问题在于 OR 运算符。由于 OR,在您的两个顶级 AND 表达式中,数据库都不能使用索引。

  1. 由于在创建记录时,它还会将 updated_at 字段设置为相同的时间戳,您可以删除 OR created_at,以便您在 update_at 上建立索引。
  2. 如果您可以按文章类型过滤父 ID 和子 ID,则可以删除这些 OR。但是,请确保您可以足够有效地执行此操作,以免花费更多时间过滤 id 列表作为输入,这样它不会比未索引查询花费更长的时间。首先尝试 1.,然后查看使用 updated_at 索引需要多长时间。

如果您同时执行 1 和 2,请务必创建一个包含所有三个字段(updated_at、parent_id 和 child_id)的索引。

【讨论】:

    猜你喜欢
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多