Class: Mxrb::Oql::PlanAnalyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/mxrb/oql/plan_analyzer.rb

Overview

Turns PostgreSQL EXPLAIN JSON into conservative, actionable diagnostics. A sequential scan is not automatically an error: small-table scans are often cheaper than an index lookup, so estimates and measured rows decide whether MXRB emits a hint or a warning.

Constant Summary collapse

LARGE_ROWS =

rubocop:disable Metrics/ClassLength

1_000
HIGH_COST =
1_000.0
MISESTIMATE_RATIO =
10.0
METRIC_KEYS =
[
  'Plan Rows', 'Actual Rows', 'Actual Loops', 'Rows Removed by Filter',
  'Startup Cost', 'Total Cost', 'Actual Total Time', 'Sort Space Used', 'Sort Space Type'
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(indexes: []) ⇒ PlanAnalyzer

Returns a new instance of PlanAnalyzer.



30
31
32
# File 'lib/mxrb/oql/plan_analyzer.rb', line 30

def initialize(indexes: [])
  @indexes = Array(indexes).freeze
end

Instance Method Details

#analyze(payload, analyzed: false) ⇒ Object

Raises:

  • (ArgumentError)


34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/mxrb/oql/plan_analyzer.rb', line 34

def analyze(payload, analyzed: false)
  envelope = Array(payload).first
  raise ArgumentError, 'invalid PostgreSQL EXPLAIN JSON' unless envelope.is_a?(Hash)

  root = envelope['Plan']
  raise ArgumentError, 'PostgreSQL EXPLAIN JSON has no Plan' unless root.is_a?(Hash)

  findings = walk(root).flat_map { findings_for(_1) }.freeze
  PlanReport.new(
    :postgresql, analyzed, envelope['Planning Time'], envelope['Execution Time'],
    root['Total Cost'], findings, payload
  )
end