Files
danbooru/app/logical/explain_parser.rb
evazion a7dc05ce63 Enable frozen string literals.
Make all string literals immutable by default.
2021-12-14 21:33:27 -06:00

54 lines
1.5 KiB
Ruby

# frozen_string_literal: true
# Parse the output of the Postgres EXPLAIN command to get how many rows Postgres
# *thinks* a SQL query will return. This is an estimate, and only accurate for
# queries that have a single condition. If the query has multiple conditions,
# then Postgres will assume they're independent (have no overlap), which is not
# always the case.
#
# Used by {PostQueryBuilder#fast_count} to get a fast post count estimate for
# certain single metatag searches.
#
# ExplainParser.new(Post.all).query_plan
# => EXPLAIN (FORMAT JSON) SELECT "posts".* FROM "posts"
# => {
# "Node Type"=>"Seq Scan",
# "Parallel Aware"=>false,
# "Relation Name"=>"posts",
# "Alias"=>"posts",
# "Startup Cost"=>0.0,
# "Total Cost"=>780900.02,
# "Plan Rows"=>4413102,
# "Plan Width"=>1268
# }
#
# @see https://www.postgresql.org/docs/current/sql-explain.html
class ExplainParser
extend Memoist
attr_reader :relation
# @param the ActiveRecord relation
def initialize(relation)
@relation = relation
end
# @return [Hash] the Postgres query plan
def query_plan
result = ApplicationRecord.connection.select_one("EXPLAIN (FORMAT JSON) #{sql}")
json = JSON.parse(result["QUERY PLAN"])
json.first["Plan"]
end
# @return [Integer] the number of rows Postgres *thinks* the query will return
def row_count
query_plan["Plan Rows"]
end
# @return [String] the query's SQL
def sql
relation.reorder(nil).to_sql
end
memoize :query_plan
end