问题描述
在 ActiveRecord(和 Postgresql)中使用 Rails 时,执行“简单”查询会为它们添加一个名称,例如打电话
Article.all
# => Article Load (2.6ms) SELECT "articles".* FROM "articles"
将查询命名为 Article Load
。但是,当执行稍微复杂的查询时,不会生成名称,例如
Article.group(:article_group_id).count
# => (1.2ms) SELECT COUNT(*) AS count_all,"articles"."article_group_id" AS articles_article_group_id FROM "articles" GROUP BY "articles"."article_group_id"
如果使用 execute
方法执行自定义查询,我可以添加名称:
ActiveRecord::Base.connection.execute("SELECT * FROM articles","My custom query name")
# => My custom query name (2.5ms) SELECT * FROM articles
但是有没有办法将自定义名称添加到使用 ActiveRecord 方法构建的查询中?
如果您想知道为什么:该名称可用于各种监控,例如在 AppSignal 中查看慢查询时。
解决方法
由于您只想自定义查询名称以进行监控,所以我认为您只需要更改query name
方法中的ActiveRecord::ConnectionAdapters#log
,此方法是记录执行的sql查询的方法,包括 query name
。
这是我的解决方案:
# lib/active_record/base.rb
# note that MUST be base.rb
# otherwise you need to add initializer to extend Rails core
#
module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
attr_accessor :log_tag
private
alias old_log log
def log(sql,name = "SQL",binds = [],type_casted_binds = [],statement_name = nil)
if name != 'SCHEMA'
name = @log_tag
@log_tag = nil # reset
end
old_log(sql,name,binds,type_casted_binds,statement_name) do
yield
end
end
end
end
module QueryMethods
def log_tag(tag_name) # class method
spawn.log_tag(tag_name)
self
end
end
module Querying
delegate :log_tag,to: :all
end
class Relation
def log_tag(tag_name) # instance method
conn = klass.connection
conn.log_tag = tag_name
self
end
end
end
演示
Task.log_tag("DEMO").group(:status).count
# DEMO (0.7ms) SELECT COUNT(*) AS count_all,"tasks"."status" AS tasks_status FROM "tasks" GROUP BY "tasks"."status"
Task.where(status: 6).log_tag("SIX").first(20)
# SIX (0.8ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."status" = ? ORDER BY "tasks"."id" ASC LIMIT ?
Task.where(status: 6).first(20)
# (0.8ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."status" = ? ORDER BY "tasks"."id" ASC LIMIT ?
注意
如果您想为特定查询修复 query name
,您可以使用带有键的哈希是整个特定 sql 字符串(或整个 sql 的哈希,例如 Rails 核心缓存查询的方式:{{ 1}}) 并且值是您想要的 query_signature = ActiveSupport::Digest.hexdigest(to_sql)
。
query name