(其实用bullet也可以,不过顺便了解下mini_prof的运作吧)

在Gemfile加入mini_prof后,跟踪一下查询数据库时它是如何记录耗时和调用栈的

binding.trace_tree(htmp: 'mini_porfiler'){ Member.limit(1).to_a }

得调用栈如下:

20190726_161505_264_mini_porfiler.html

在其中搜索mini,得:



找到这个被重写的async_exec,发现它是使用record_sql方法收集sql及耗时

def async_exec(*args, &blk)
  return async_exec_without_profiling(*args, &blk) unless SqlPatches.should_measure?

  start        = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result       = exec_without_profiling(*args, &blk)
  elapsed_time = SqlPatches.elapsed_time(start)
  record       = ::Rack::MiniProfiler.record_sql(args[0], elapsed_time)
  result.instance_variable_set("@miniprofiler_sql_id", record) if result

  result
end

于是,我们也可以利用这个方法来收集query cache出现的地方,而因为query cache不会发出sql,不能通过重写adapter的xx_exec来拦截,但它会输出日志,所以对该输出进行拦截即可

module QueryCacheProfiler
  class Railtie < ::Rails::Railtie
    initializer "rack_mini_profiler.query_cache" do |app|
      ::ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
        opt = args[-1]
        next if opt[:name] != "CACHE"
        duration = 1000.0 * (args[2] - args[1])
        ::Rack::MiniProfiler.record_sql("(CACHE) #{opt[:sql]}", duration)
      end
    end
  end
end

甚至可以包装成一个gem来使用,这样mini_prof的结果就会带上query cache的统计:https://github.com/turnon/query_cache_profiler