问题描述
我想测试某段代码是否执行尽可能少的 SQL 查询.
I'd like to test that a certain piece of code performs as few SQL queries as possible.
ActiveRecord::TestCase
似乎有它自己的 assert_queries
方法,它可以做到这一点.但是因为我没有修补 ActiveRecord,所以它对我没什么用.
ActiveRecord::TestCase
seems to have its own assert_queries
method, which will do just that. But since I'm not patching ActiveRecord, it's of little use to me.
RSpec 或 ActiveRecord 是否提供任何官方、公开的方法来计算在代码块中执行的 SQL 查询的数量?
Does RSpec or ActiveRecord provide any official, public means of counting the number of SQL queries performed in a block of code?
推荐答案
我想你通过提到 assert_queries
回答了你自己的问题,但这里是:
I think you answered your own question by mentioning assert_queries
, but here goes:
我建议您查看 assert_queries
背后的代码,并使用它来构建您自己的方法,您可以用它来计算查询.这里涉及的主要魔法是这一行:
I would recommend taking a look at the code behind assert_queries
and using that to build your own method which you can use to count queries. The main magic involved here is this line:
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
今天早上我做了一些修补,撕掉了 ActiveRecord 中进行查询计数的部分,然后想出了这个:
I had a bit of a tinker this morning and ripped out the parts of ActiveRecord that do the query counting and came up with this:
module ActiveRecord
class QueryCounter
cattr_accessor :query_count do
0
end
IGNORED_SQL = [/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/]
def call(name, start, finish, message_id, values)
# FIXME: this seems bad. we should probably have a better way to indicate
# the query was cached
unless 'CACHE' == values[:name]
self.class.query_count += 1 unless IGNORED_SQL.any? { |r| values[:sql] =~ r }
end
end
end
end
ActiveSupport::Notifications.subscribe('sql.active_record', ActiveRecord::QueryCounter.new)
module ActiveRecord
class Base
def self.count_queries(&block)
ActiveRecord::QueryCounter.query_count = 0
yield
ActiveRecord::QueryCounter.query_count
end
end
end
您可以在任何地方引用 ActiveRecord::Base.count_queries
方法.向它传递一个块,在其中运行您的查询,它将返回已执行的查询数:
You will be able to reference the ActiveRecord::Base.count_queries
method anywhere. Pass it a block wherein your queries are run and it will return the number of queries that have been executed:
ActiveRecord::Base.count_queries do
Ticket.first
end
为我返回1".要完成这项工作:将它放在 lib/active_record/query_counter.rb
的文件中,并像这样在 config/application.rb
文件中要求它:
Returns "1" for me. To make this work: put it in a file at lib/active_record/query_counter.rb
and require it in your config/application.rb
file like this:
require 'active_record/query_counter'
嘿,快点!
可能需要一些解释.当我们调用这条线时:
A little bit of explanation probably is required. When we call this line:
ActiveSupport::Notifications.subscribe('sql.active_record', ActiveRecord::QueryCounter.new)
我们使用了 Rails 3 的小通知框架.这是 Rails 最新主要版本的一个闪亮的小补充,没有人真正知道.它允许我们使用 subscribe
方法订阅 Rails 中的事件通知.我们将要订阅的事件作为第一个参数传入,然后将响应 call
的任何对象作为第二个参数传入.
We hook into Rails 3's little notifications framework. It's a shiny little addition to the latest major version of Rails that nobody really knows about. It allows us to subscribe to notifications of events within Rails by using the subscribe
method. We pass in the event we want to subscribe to as the first argument then any object that responds to call
as the second.
在这种情况下,当执行查询时,我们的小查询计数器将尽职尽责地增加 ActiveRecord::QueryCounter.query_count 变量,但仅适用于真实查询.
In this case when a query is executed our little query counter will dutifully increment the ActiveRecord::QueryCounter.query_count variable, but only for the real queries.
无论如何,这很有趣.希望对你有用.
Anyway, this was fun. I hope it comes useful to you.
这篇关于计算执行的查询数量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!