diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 959095679a..35264dcc72 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -395,13 +395,14 @@ PREPARE query(int, int) AS SELECT sum(bar) FROM test EXPLAIN ANALYZE EXECUTE query(100, 200); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- - HashAggregate (cost=39.53..39.53 rows=1 width=8) (actual time=0.661..0.672 rows=7 loops=1) - -> Index Scan using test_pkey on test (cost=0.00..32.97 rows=1311 width=8) (actual time=0.050..0.395 rows=99 loops=1) + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + HashAggregate (cost=9.54..9.54 rows=1 width=8) (actual time=0.156..0.161 rows=11 loops=1) + Group Key: foo + -> Index Scan using test_pkey on test (cost=0.29..9.29 rows=50 width=8) (actual time=0.039..0.091 rows=99 loops=1) Index Cond: ((id > $1) AND (id < $2)) - Total runtime: 0.851 ms -(4 rows) + Total runtime: 0.225 ms +(5 rows) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index bd5428de97..9969a251a7 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -76,9 +76,13 @@ static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es); static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es); -static void show_sort_keys_common(PlanState *planstate, - int nkeys, AttrNumber *keycols, - List *ancestors, ExplainState *es); +static void show_agg_keys(AggState *astate, List *ancestors, + ExplainState *es); +static void show_group_keys(GroupState *gstate, List *ancestors, + ExplainState *es); +static void show_sort_group_keys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + List *ancestors, ExplainState *es); static void show_sort_info(SortState *sortstate, ExplainState *es); static void show_hash_info(HashState *hashstate, ExplainState *es); static void show_instrumentation_count(const char *qlabel, int which, @@ -1341,7 +1345,14 @@ ExplainNode(PlanState *planstate, List *ancestors, planstate, es); break; case T_Agg: + show_agg_keys((AggState *) planstate, ancestors, es); + show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); + if (plan->qual) + show_instrumentation_count("Rows Removed by Filter", 1, + planstate, es); + break; case T_Group: + show_group_keys((GroupState *) planstate, ancestors, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, @@ -1693,9 +1704,9 @@ show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es) { Sort *plan = (Sort *) sortstate->ss.ps.plan; - show_sort_keys_common((PlanState *) sortstate, - plan->numCols, plan->sortColIdx, - ancestors, es); + show_sort_group_keys((PlanState *) sortstate, "Sort Key", + plan->numCols, plan->sortColIdx, + ancestors, es); } /* @@ -1707,14 +1718,56 @@ show_merge_append_keys(MergeAppendState *mstate, List *ancestors, { MergeAppend *plan = (MergeAppend *) mstate->ps.plan; - show_sort_keys_common((PlanState *) mstate, - plan->numCols, plan->sortColIdx, - ancestors, es); + show_sort_group_keys((PlanState *) mstate, "Sort Key", + plan->numCols, plan->sortColIdx, + ancestors, es); } +/* + * Show the grouping keys for an Agg node. + */ static void -show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols, - List *ancestors, ExplainState *es) +show_agg_keys(AggState *astate, List *ancestors, + ExplainState *es) +{ + Agg *plan = (Agg *) astate->ss.ps.plan; + + if (plan->numCols > 0) + { + /* The key columns refer to the tlist of the child plan */ + ancestors = lcons(astate, ancestors); + show_sort_group_keys(outerPlanState(astate), "Group Key", + plan->numCols, plan->grpColIdx, + ancestors, es); + ancestors = list_delete_first(ancestors); + } +} + +/* + * Show the grouping keys for a Group node. + */ +static void +show_group_keys(GroupState *gstate, List *ancestors, + ExplainState *es) +{ + Group *plan = (Group *) gstate->ss.ps.plan; + + /* The key columns refer to the tlist of the child plan */ + ancestors = lcons(gstate, ancestors); + show_sort_group_keys(outerPlanState(gstate), "Group Key", + plan->numCols, plan->grpColIdx, + ancestors, es); + ancestors = list_delete_first(ancestors); +} + +/* + * Common code to show sort/group keys, which are represented in plan nodes + * as arrays of targetlist indexes + */ +static void +show_sort_group_keys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + List *ancestors, ExplainState *es) { Plan *plan = planstate->plan; List *context; @@ -1748,7 +1801,7 @@ show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols, result = lappend(result, exprstr); } - ExplainPropertyList("Sort Key", result, es); + ExplainPropertyList(qlabel, result, es); } /* diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index c05b39cb89..1a0ca5c5f3 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -659,12 +659,13 @@ explain (costs off) QUERY PLAN --------------------------------------------------------------------- HashAggregate + Group Key: $0 InitPlan 1 (returns $0) -> Limit -> Index Only Scan Backward using tenk1_unique2 on tenk1 Index Cond: (unique2 IS NOT NULL) -> Result -(6 rows) +(7 rows) select distinct max(unique2) from tenk1; max @@ -806,6 +807,7 @@ explain (costs off) QUERY PLAN ---------------------------------------------------------------------------------------------- HashAggregate + Group Key: $0, $1 InitPlan 1 (returns $0) -> Limit -> Merge Append @@ -831,7 +833,7 @@ explain (costs off) -> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1 Index Cond: (f1 IS NOT NULL) -> Result -(26 rows) +(27 rows) select distinct min(f1), max(f1) from minmaxtest; min | max diff --git a/src/test/regress/expected/matview.out b/src/test/regress/expected/matview.out index 9ba2b9a7b4..31751ebd9e 100644 --- a/src/test/regress/expected/matview.out +++ b/src/test/regress/expected/matview.out @@ -22,8 +22,9 @@ EXPLAIN (costs off) QUERY PLAN --------------------- HashAggregate + Group Key: type -> Seq Scan on t -(2 rows) +(3 rows) CREATE MATERIALIZED VIEW tm AS SELECT type, sum(amt) AS totamt FROM t GROUP BY type WITH NO DATA; SELECT relispopulated FROM pg_class WHERE oid = 'tm'::regclass; @@ -59,8 +60,9 @@ EXPLAIN (costs off) Sort Sort Key: t.type -> HashAggregate + Group Key: t.type -> Seq Scan on t -(4 rows) +(5 rows) CREATE MATERIALIZED VIEW tvm AS SELECT * FROM tv ORDER BY type; SELECT * FROM tvm; @@ -82,8 +84,9 @@ EXPLAIN (costs off) --------------------------- Aggregate -> HashAggregate + Group Key: t.type -> Seq Scan on t -(3 rows) +(4 rows) CREATE MATERIALIZED VIEW tvvm AS SELECT * FROM tvv; CREATE VIEW tvvmv AS SELECT * FROM tvvm; diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index ae690cf968..6f9ee5eb47 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -494,12 +494,13 @@ explain (costs off) QUERY PLAN --------------------------------------------------- HashAggregate + Group Key: ((t1.a || t1.b)) -> Append -> Index Scan using t1_ab_idx on t1 Index Cond: ((a || b) = 'ab'::text) -> Index Only Scan using t2_pkey on t2 Index Cond: (ab = 'ab'::text) -(6 rows) +(7 rows) reset enable_seqscan; reset enable_indexscan; @@ -552,17 +553,18 @@ SELECT * FROM SELECT 2 AS t, 4 AS x) ss WHERE x < 4 ORDER BY x; - QUERY PLAN --------------------------------- + QUERY PLAN +-------------------------------------------------------- Sort Sort Key: ss.x -> Subquery Scan on ss Filter: (ss.x < 4) -> HashAggregate + Group Key: (1), (generate_series(1, 10)) -> Append -> Result -> Result -(8 rows) +(9 rows) SELECT * FROM (SELECT 1 AS t, generate_series(1,10) AS x diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index 1e6365b4f9..0f21fcb01d 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -619,12 +619,13 @@ explain (costs off) select first_value(max(x)) over (), y from (select unique1 as x, ten+four as y from tenk1) ss group by y; - QUERY PLAN -------------------------------- + QUERY PLAN +--------------------------------------------- WindowAgg -> HashAggregate + Group Key: (tenk1.ten + tenk1.four) -> Seq Scan on tenk1 -(3 rows) +(4 rows) -- test non-default frame specifications SELECT four, ten,