Ruby on rails ActiveRecord::Relation#explain始终完整运行查询
我试图使用Rails3和Rails4中的explain方法来估计在一个特别昂贵的查询中返回的行数。它连接3个表,可能导致1000万行表的表扫描,这与count()聚合结合起来特别慢(数据库是Postgres 9.3) 我的问题是这个。如果我使用内置的explain()方法,查询总是在返回结果之前在后台完全运行。这可能需要2分钟以上。在其他情况下,我要分析的查询可能需要数小时才能运行(例如,对于报告) 我有一个稍微难看的解决方案,我对sql做了一个修改,在前面加上“explain”,然后执行查询。这适用于Rails 3,但需要对Rails 4进行一些返工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”,然后执行查询。
所以我想我的问题是。有没有办法让内置的AR explain()方法实现我想要的功能,有没有其他优雅的方法来实现这一功能,或者这是AR::explain()中的一个bug,需要在某个时候记录并修复?我不确定是否有一个方法可以异步实现这一功能。但是,使用resque或sidekiq异步运行查询肯定会让您受益匪浅 以下是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能做到这一点(而且不能用选项关闭)