Summarizes a decoded Postgres EXPLAIN (FORMAT JSON) result into a value-free
plan digest — node types, relation names and row estimates only, never any
row data.
The plan fingerprint hashes ONLY the structural tree (node types + relation
names in traversal order), so it is stable across runs regardless of cost or
row-count variance. This is what lets mix excessibility.digest.compare flag a
plan change under stable SQL.
Tolerant by construction: it accepts both the raw list-wrapped Postgres form
([%{"Plan" => ...}]) and an already-unwrapped %{"Plan" => ...} map, and
returns nil on anything unparseable rather than raising.
Summary
Functions
Aggregate the plan summaries of every occurrence of one query fingerprint into a single, bounded, value-free summary.
Aggregate every occurrence of one query fingerprint into the bounded set of distinct structural plan variants, one representative per structure.
Turn a decoded EXPLAIN (FORMAT JSON) result into a value-free plan summary.
Functions
Aggregate the plan summaries of every occurrence of one query fingerprint into a single, bounded, value-free summary.
A query fingerprint can fire many times in one journey; each occurrence carries
its own plan summary, and a later occurrence can do far more row work than the
first (issue #167). Selecting only the first occurrence's plan discards that
magnitude before comparison ever runs, so aggregation keeps the maximum
comparable row work per structural node path: estimated/actual rows, loops and
rows_touched are maxed position-by-position across occurrences that share a
plan structural fingerprint. max/2 is commutative, so the result is
independent of occurrence order.
When occurrences carry different plan structures (e.g. the planner flipped to
a different plan), they are grouped by structural fingerprint, each group is
aggregated, and the group doing the most total row work is chosen as the
deterministic representative (ties broken by fingerprint). Returns nil for an
empty list and the sole summary unchanged for a single (or all-identical)
occurrence.
Aggregate every occurrence of one query fingerprint into the bounded set of distinct structural plan variants, one representative per structure.
A parameterized query can pick different plans by selectivity, so one SQL
fingerprint legitimately carries several plan structures across a journey.
aggregate/1 collapses them to the single heaviest representative, which
discards any non-dominant variant that changed or regressed (issue #173). This
keeps them all: occurrences are grouped by structural fingerprint, each group
is merged by keeping the maximum comparable row work per node path (the
same merge_summary/2 used by aggregate/1, so the heaviest instance of each
structure survives), and the resulting representatives are returned sorted by
fingerprint for determinism. Returns [] for an empty list.
Turn a decoded EXPLAIN (FORMAT JSON) result into a value-free plan summary.
Returns nil for any input that does not contain a parseable "Plan" root.