Ruby on rails ActiveRecord::Relation#explain始终完整运行查询

Ruby on rails ActiveRecord::Relation#explain始终完整运行查询,ruby-on-rails,postgresql,activerecord,explain,Ruby On Rails,Postgresql,Activerecord,Explain,我试图使用Rails3和Rails4中的explain方法来估计在一个特别昂贵的查询中返回的行数。它连接3个表,可能导致1000万行表的表扫描,这与count()聚合结合起来特别慢(数据库是Postgres 9.3) 我的问题是这个。如果我使用内置的explain()方法,查询总是在返回结果之前在后台完全运行。这可能需要2分钟以上。在其他情况下,我要分析的查询可能需要数小时才能运行(例如,对于报告) 我有一个稍微难看的解决方案,我对sql做了一个修改,在前面加上“explain”,然后执行查询。

我试图使用Rails3和Rails4中的explain方法来估计在一个特别昂贵的查询中返回的行数。它连接3个表,可能导致1000万行表的表扫描,这与count()聚合结合起来特别慢(数据库是Postgres 9.3)

我的问题是这个。如果我使用内置的explain()方法,查询总是在返回结果之前在后台完全运行。这可能需要2分钟以上。在其他情况下,我要分析的查询可能需要数小时才能运行(例如,对于报告)

我有一个稍微难看的解决方案,我对sql做了一个修改,在前面加上“explain”,然后执行查询。这适用于Rails 3,但需要对Rails 4进行一些返工


所以我想我的问题是。有没有办法让内置的AR explain()方法实现我想要的功能,有没有其他优雅的方法来实现这一功能,或者这是AR::explain()中的一个bug,需要在某个时候记录并修复?

我不确定是否有一个方法可以异步实现这一功能。但是,使用resquesidekiq异步运行查询肯定会让您受益匪浅

以下是resque的链接:

以下是sidekiq的链接:

以下是我是如何做到这一点的。 在Rails3和Rails4中,我为ActiveRecord::Relation编写了一个初始值设定项

首先,在Rails 3中:

class ActiveRecord::Relation
  HUGE_COUNT = 20000

  def count(column_name = nil, options = {})
    exact, has_conditions = false, false
    h = (column_name.class == Hash ? column_name : options)
    exact = h[:exact]
    has_conditions = h[:conditions]
    has_distinct = (column_name.class == String) && (column_name =~ /\bdistinct\b/i)
    h = h.except(:exact) # Remove it because super won't understand it
    column_name.class == Hash ? column_name = h : options = h
    if exact || has_conditions || has_distinct
      super
    else
      est = estimated_count
      est > HUGE_COUNT ? est : super
    end
  end

  def estimated_count
    node = connection.execute("EXPLAIN #{self.to_sql}").first
    match = node['QUERY PLAN'].match(/rows=\d+\b/)
    match ? match[0].split('=').last.to_i : 0
  end
结束

Rails 4与之相同,只是:

  def estimated_count
    node = {}
    connection.unprepared_statement do
      node = connection.execute("EXPLAIN #{self.to_sql}").first
    end
    match = node['QUERY PLAN'].match(/rows=\d+\b/)
    match ? match[0].split('=').last.to_i : 0
  end

巨大的_计数很低,因为到目前为止,我发现这通常非常准确,在1%或2%以内。这对我的需要来说很好,但显然这是相当危险的…

它完全运行查询的原因是ActiveRecord
.explain
是为运行查询而设计的。它与SQL
解释不同。它更像是SQL
解释分析

正如报告所说

explain实际执行查询,然后请求查询计划


谢谢Rico,但我真的需要同步进行。我用to_sql解决了这个问题,所以我会写下我自己的答案。我不敢相信rails能做到这一点(而且不能用选项关闭)