diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c index bb44393df..e0cdfbf57 100644 --- a/src/backend/distributed/planner/multi_explain.c +++ b/src/backend/distributed/planner/multi_explain.c @@ -182,6 +182,8 @@ MultiExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, return; } + ExplainOpenGroup("Distributed Query", NULL, true, es); + if (es->format == EXPLAIN_FORMAT_TEXT) { appendStringInfoSpaces(es->str, es->indent * 2); @@ -246,13 +248,19 @@ MultiExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, es->indent += 1; } + ExplainOpenGroup("Master Query", "Master Query", false, es); + ExplainMasterPlan(masterPlan, into, es, queryString, params, &planDuration); + ExplainCloseGroup("Master Query", "Master Query", false, es); + if (es->format == EXPLAIN_FORMAT_TEXT) { es->indent -= 1; } } + + ExplainCloseGroup("Distributed Query", NULL, true, es); } @@ -390,7 +398,7 @@ ExplainJob(Job *job, ExplainState *es) List *taskList = job->taskList; int taskCount = list_length(taskList); - ExplainOpenGroup("Job", NULL, true, es); + ExplainOpenGroup("Job", "Job", true, es); ExplainPropertyInteger("Task Count", taskCount, es); @@ -423,19 +431,25 @@ ExplainJob(Job *job, ExplainState *es) ExplainCloseGroup("Tasks", "Tasks", false, es); } - - ExplainCloseGroup("Job", NULL, true, es); - - /* show explain output for depended jobs, if any */ - foreach(dependedJobCell, dependedJobList) + else { - Job *dependedJob = (Job *) lfirst(dependedJobCell); + ExplainOpenGroup("Depended Jobs", "Depended Jobs", false, es); - if (CitusIsA(dependedJob, MapMergeJob)) + /* show explain output for depended jobs, if any */ + foreach(dependedJobCell, dependedJobList) { - ExplainMapMergeJob((MapMergeJob *) dependedJob, es); + Job *dependedJob = (Job *) lfirst(dependedJobCell); + + if (CitusIsA(dependedJob, MapMergeJob)) + { + ExplainMapMergeJob((MapMergeJob *) dependedJob, es); + } } + + ExplainCloseGroup("Depended Jobs", "Depended Jobs", false, es); } + + ExplainCloseGroup("Job", "Job", true, es); } @@ -449,6 +463,7 @@ static void ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es) { List *dependedJobList = mapMergeJob->job.dependedJobList; + int dependedJobCount = list_length(dependedJobList); ListCell *dependedJobCell = NULL; int mapTaskCount = list_length(mapMergeJob->mapTaskList); int mergeTaskCount = list_length(mapMergeJob->mergeTaskList); @@ -465,18 +480,25 @@ ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es) ExplainPropertyInteger("Map Task Count", mapTaskCount, es); ExplainPropertyInteger("Merge Task Count", mergeTaskCount, es); - ExplainCloseGroup("Job", NULL, true, es); - - foreach(dependedJobCell, dependedJobList) + if (dependedJobCount > 0) { - Job *dependedJob = (Job *) lfirst(dependedJobCell); + ExplainOpenGroup("Depended Jobs", "Depended Jobs", false, es); - if (CitusIsA(dependedJob, MapMergeJob)) + foreach(dependedJobCell, dependedJobList) { - ExplainMapMergeJob((MapMergeJob *) dependedJob, es); + Job *dependedJob = (Job *) lfirst(dependedJobCell); + + if (CitusIsA(dependedJob, MapMergeJob)) + { + ExplainMapMergeJob((MapMergeJob *) dependedJob, es); + } } + + ExplainCloseGroup("Depended Jobs", "Depended Jobs", false, es); } + ExplainCloseGroup("MapMergeJob", NULL, true, es); + if (es->format == EXPLAIN_FORMAT_TEXT) { es->indent -= 3; diff --git a/src/test/regress/expected/multi_explain.out b/src/test/regress/expected/multi_explain.out index 58fb90d64..8ea35368a 100644 --- a/src/test/regress/expected/multi_explain.out +++ b/src/test/regress/expected/multi_explain.out @@ -4,6 +4,28 @@ \a\t SET citus.task_executor_type TO 'real-time'; SET citus.explain_distributed_queries TO on; +-- Function that parses explain output as JSON +CREATE FUNCTION explain_json(query text) +RETURNS jsonb +AS $BODY$ +DECLARE + result jsonb; +BEGIN + EXECUTE format('EXPLAIN (FORMAT JSON) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; +-- Function that parses explain output as XML +CREATE FUNCTION explain_xml(query text) +RETURNS xml +AS $BODY$ +DECLARE + result xml; +BEGIN + EXECUTE format('EXPLAIN (FORMAT XML) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; -- Test Text format EXPLAIN (COSTS FALSE, FORMAT TEXT) SELECT l_quantity, count(*) count_quantity FROM lineitem @@ -28,165 +50,185 @@ EXPLAIN (COSTS FALSE, FORMAT JSON) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; [ - "Executor": "Real-Time", { - "Task Count": 6, - "Tasks Shown": "One of 6", - "Tasks": [ - { - "Node": "host=localhost port=57637 dbname=regression", - "Remote Plan": [ - [ - { - "Plan": { - "Node Type": "Aggregate", - "Strategy": "Hashed", - "Group Key": ["l_quantity"], - "Plans": [ - { - "Node Type": "Seq Scan", - "Parent Relationship": "Outer", - "Relation Name": "lineitem_102010", - "Alias": "lineitem" - } - ] - } - } - ] - - ] - } - ] - }, - { - "Plan": { - "Node Type": "Sort", - "Sort Key": ["(sum(((sum(intermediate_column_41_1))::bigint)))::bigint", "intermediate_column_41_0"], - "Plans": [ + "Executor": "Real-Time", + "Job": { + "Task Count": 6, + "Tasks Shown": "One of 6", + "Tasks": [ { - "Node Type": "Aggregate", - "Strategy": "Hashed", - "Parent Relationship": "Outer", - "Group Key": ["intermediate_column_41_0"], - "Plans": [ - { - "Node Type": "Seq Scan", - "Parent Relationship": "Outer", - "Relation Name": "pg_merge_job_0041", - "Alias": "pg_merge_job_0041" - } + "Node": "host=localhost port=57637 dbname=regression", + "Remote Plan": [ + [ + { + "Plan": { + "Node Type": "Aggregate", + "Strategy": "Hashed", + "Group Key": ["l_quantity"], + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "lineitem_102010", + "Alias": "lineitem" + } + ] + } + } + ] + ] } ] - } + }, + "Master Query": [ + { + "Plan": { + "Node Type": "Sort", + "Sort Key": ["(sum(((sum(intermediate_column_41_1))::bigint)))::bigint", "intermediate_column_41_0"], + "Plans": [ + { + "Node Type": "Aggregate", + "Strategy": "Hashed", + "Parent Relationship": "Outer", + "Group Key": ["intermediate_column_41_0"], + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "pg_merge_job_0041", + "Alias": "pg_merge_job_0041" + } + ] + } + ] + } + } + ] } ] +-- Validate JSON format +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); +t -- Test XML format EXPLAIN (COSTS FALSE, FORMAT XML) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; - Real-Time - - 6 - One of 6 - - - host=localhost port=57637 dbname=regression - - - - - Aggregate - Hashed - - l_quantity - - - - Seq Scan - Outer - lineitem_102010 - lineitem - - - - - - - - - - - - Sort - - (sum(((sum(intermediate_column_42_1))::bigint)))::bigint - intermediate_column_42_0 - - + + Real-Time + + 6 + One of 6 + + + host=localhost port=57637 dbname=regression + + + + + Aggregate + Hashed + + l_quantity + + + + Seq Scan + Outer + lineitem_102010 + lineitem + + + + + + + + + + + - Aggregate - Hashed - Outer - - intermediate_column_42_0 - + Sort + + (sum(((sum(intermediate_column_43_1))::bigint)))::bigint + intermediate_column_43_0 + - Seq Scan + Aggregate + Hashed Outer - pg_merge_job_0042 - pg_merge_job_0042 + + intermediate_column_43_0 + + + + Seq Scan + Outer + pg_merge_job_0043 + pg_merge_job_0043 + + - - - + + + +-- Validate XML format +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); +t -- Test YAML format EXPLAIN (COSTS FALSE, FORMAT YAML) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; -Executor: "Real-Time" -- Task Count: 6 - Tasks Shown: "One of 6" - Tasks: - - Node: "host=localhost port=57637 dbname=regression" - Remote Plan: - - Plan: - Node Type: "Aggregate" +- Executor: "Real-Time" + Job: + Task Count: 6 + Tasks Shown: "One of 6" + Tasks: + - Node: "host=localhost port=57637 dbname=regression" + Remote Plan: + - Plan: + Node Type: "Aggregate" + Strategy: "Hashed" + Group Key: + - "l_quantity" + Plans: + - Node Type: "Seq Scan" + Parent Relationship: "Outer" + Relation Name: "lineitem_102010" + Alias: "lineitem" + + Master Query: + - Plan: + Node Type: "Sort" + Sort Key: + - "(sum(((sum(intermediate_column_45_1))::bigint)))::bigint" + - "intermediate_column_45_0" + Plans: + - Node Type: "Aggregate" Strategy: "Hashed" + Parent Relationship: "Outer" Group Key: - - "l_quantity" + - "intermediate_column_45_0" Plans: - Node Type: "Seq Scan" Parent Relationship: "Outer" - Relation Name: "lineitem_102010" - Alias: "lineitem" - -- Plan: - Node Type: "Sort" - Sort Key: - - "(sum(((sum(intermediate_column_43_1))::bigint)))::bigint" - - "intermediate_column_43_0" - Plans: - - Node Type: "Aggregate" - Strategy: "Hashed" - Parent Relationship: "Outer" - Group Key: - - "intermediate_column_43_0" - Plans: - - Node Type: "Seq Scan" - Parent Relationship: "Outer" - Relation Name: "pg_merge_job_0043" - Alias: "pg_merge_job_0043" + Relation Name: "pg_merge_job_0045" + Alias: "pg_merge_job_0045" -- Test Text format EXPLAIN (COSTS FALSE, FORMAT TEXT) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; -Distributed Query into pg_merge_job_0044 +Distributed Query into pg_merge_job_0046 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -197,14 +239,14 @@ Distributed Query into pg_merge_job_0044 -> Seq Scan on lineitem_102010 lineitem Master Query -> Sort - Sort Key: (sum(((sum(intermediate_column_44_1))::bigint)))::bigint, intermediate_column_44_0 + Sort Key: (sum(((sum(intermediate_column_46_1))::bigint)))::bigint, intermediate_column_46_0 -> HashAggregate - Group Key: intermediate_column_44_0 - -> Seq Scan on pg_merge_job_0044 + Group Key: intermediate_column_46_0 + -> Seq Scan on pg_merge_job_0046 -- Test verbose EXPLAIN (COSTS FALSE, VERBOSE TRUE) SELECT sum(l_quantity) / avg(l_quantity) FROM lineitem; -Distributed Query into pg_merge_job_0045 +Distributed Query into pg_merge_job_0047 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -216,15 +258,15 @@ Distributed Query into pg_merge_job_0045 Output: l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment Master Query -> Aggregate - Output: (sum(intermediate_column_45_0) / (sum(intermediate_column_45_1) / sum(intermediate_column_45_2))) - -> Seq Scan on pg_temp_2.pg_merge_job_0045 - Output: intermediate_column_45_0, intermediate_column_45_1, intermediate_column_45_2 + Output: (sum(intermediate_column_47_0) / (sum(intermediate_column_47_1) / sum(intermediate_column_47_2))) + -> Seq Scan on pg_temp_2.pg_merge_job_0047 + Output: intermediate_column_47_0, intermediate_column_47_1, intermediate_column_47_2 -- Test join EXPLAIN (COSTS FALSE) SELECT * FROM lineitem JOIN orders ON l_orderkey = o_orderkey AND l_quantity < 5 ORDER BY l_quantity DESC LIMIT 10; -Distributed Query into pg_merge_job_0046 +Distributed Query into pg_merge_job_0048 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -242,8 +284,8 @@ Distributed Query into pg_merge_job_0046 Master Query -> Limit -> Sort - Sort Key: intermediate_column_46_4 DESC - -> Seq Scan on pg_merge_job_0046 + Sort Key: intermediate_column_48_4 DESC + -> Seq Scan on pg_merge_job_0048 -- Test insert EXPLAIN (COSTS FALSE) INSERT INTO lineitem VALUES(1,0); @@ -291,7 +333,7 @@ Distributed Query -- Test single-shard SELECT EXPLAIN (COSTS FALSE) SELECT l_quantity FROM lineitem WHERE l_orderkey = 5; -Distributed Query into pg_merge_job_0047 +Distributed Query into pg_merge_job_0049 Executor: Router Task Count: 1 Tasks Shown: All @@ -301,11 +343,17 @@ Distributed Query into pg_merge_job_0047 Recheck Cond: (l_orderkey = 5) -> Bitmap Index Scan on lineitem_pkey_102009 Index Cond: (l_orderkey = 5) +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); +t +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); +t -- Test CREATE TABLE ... AS EXPLAIN (COSTS FALSE) CREATE TABLE explain_result AS SELECT * FROM lineitem; -Distributed Query into pg_merge_job_0048 +Distributed Query into pg_merge_job_0052 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -313,12 +361,12 @@ Distributed Query into pg_merge_job_0048 Node: host=localhost port=57637 dbname=regression -> Seq Scan on lineitem_102010 lineitem Master Query - -> Seq Scan on pg_merge_job_0048 + -> Seq Scan on pg_merge_job_0052 -- Test all tasks output SET citus.explain_all_tasks TO on; EXPLAIN (COSTS FALSE) SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030; -Distributed Query into pg_merge_job_0049 +Distributed Query into pg_merge_job_0053 Executor: Real-Time Task Count: 3 Tasks Shown: All @@ -339,13 +387,19 @@ Distributed Query into pg_merge_job_0049 Filter: (l_orderkey > 9030) Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0049 + -> Seq Scan on pg_merge_job_0053 +SELECT true AS valid FROM explain_xml($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); +t +SELECT true AS valid FROM explain_json($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); +t -- Test track tracker SET citus.task_executor_type TO 'task-tracker'; SET citus.explain_all_tasks TO off; EXPLAIN (COSTS FALSE) SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030; -Distributed Query into pg_merge_job_0050 +Distributed Query into pg_merge_job_0056 Executor: Task-Tracker Task Count: 3 Tasks Shown: One of 3 @@ -356,7 +410,7 @@ Distributed Query into pg_merge_job_0050 Filter: (l_orderkey > 9030) Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0050 + -> Seq Scan on pg_merge_job_0056 -- Test re-partition join SET citus.large_table_shard_count TO 1; EXPLAIN (COSTS FALSE) @@ -365,7 +419,7 @@ EXPLAIN (COSTS FALSE) WHERE l_orderkey = o_orderkey AND o_custkey = c_custkey AND l_suppkey = s_suppkey; -Distributed Query into pg_merge_job_0053 +Distributed Query into pg_merge_job_0059 Executor: Task-Tracker Task Count: 1 Tasks Shown: None, not supported for re-partition queries @@ -377,4 +431,129 @@ Distributed Query into pg_merge_job_0053 Merge Task Count: 1 Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0053 + -> Seq Scan on pg_merge_job_0059 +EXPLAIN (COSTS FALSE, FORMAT JSON) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; +[ + { + "Executor": "Task-Tracker", + "Job": { + "Task Count": 1, + "Tasks Shown": "None, not supported for re-partition queries", + "Depended Jobs": [ + { + "Map Task Count": 1, + "Merge Task Count": 1, + "Depended Jobs": [ + { + "Map Task Count": 6, + "Merge Task Count": 1 + } + ] + } + ] + }, + "Master Query": [ + { + "Plan": { + "Node Type": "Aggregate", + "Strategy": "Plain", + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "pg_merge_job_0062", + "Alias": "pg_merge_job_0062" + } + ] + } + } + ] + } +] +SELECT true AS valid FROM explain_json($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); +t +EXPLAIN (COSTS FALSE, FORMAT XML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; + + + Task-Tracker + + 1 + None, not supported for re-partition queries + + + 1 + 1 + + + 6 + 1 + + + + + + + + + Aggregate + Plain + + + Seq Scan + Outer + pg_merge_job_0068 + pg_merge_job_0068 + + + + + + + +SELECT true AS valid FROM explain_xml($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); +t +EXPLAIN (COSTS FALSE, FORMAT YAML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; +- Executor: "Task-Tracker" + Job: + Task Count: 1 + Tasks Shown: "None, not supported for re-partition queries" + Depended Jobs: + - Map Task Count: 1 + Merge Task Count: 1 + Depended Jobs: + - Map Task Count: 6 + Merge Task Count: 1 + Master Query: + - Plan: + Node Type: "Aggregate" + Strategy: "Plain" + Plans: + - Node Type: "Seq Scan" + Parent Relationship: "Outer" + Relation Name: "pg_merge_job_0074" + Alias: "pg_merge_job_0074" diff --git a/src/test/regress/expected/multi_explain_0.out b/src/test/regress/expected/multi_explain_0.out index 88831924f..250678e0f 100644 --- a/src/test/regress/expected/multi_explain_0.out +++ b/src/test/regress/expected/multi_explain_0.out @@ -4,6 +4,28 @@ \a\t SET citus.task_executor_type TO 'real-time'; SET citus.explain_distributed_queries TO on; +-- Function that parses explain output as JSON +CREATE FUNCTION explain_json(query text) +RETURNS jsonb +AS $BODY$ +DECLARE + result jsonb; +BEGIN + EXECUTE format('EXPLAIN (FORMAT JSON) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; +-- Function that parses explain output as XML +CREATE FUNCTION explain_xml(query text) +RETURNS xml +AS $BODY$ +DECLARE + result xml; +BEGIN + EXECUTE format('EXPLAIN (FORMAT XML) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; -- Test Text format EXPLAIN (COSTS FALSE, FORMAT TEXT) SELECT l_quantity, count(*) count_quantity FROM lineitem @@ -28,165 +50,185 @@ EXPLAIN (COSTS FALSE, FORMAT JSON) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; [ - "Executor": "Real-Time", { - "Task Count": 6, - "Tasks Shown": "One of 6", - "Tasks": [ - { - "Node": "host=localhost port=57637 dbname=regression", - "Remote Plan": [ - [ - { - "Plan": { - "Node Type": "Aggregate", - "Strategy": "Hashed", - "Group Key": ["l_quantity"], - "Plans": [ - { - "Node Type": "Seq Scan", - "Parent Relationship": "Outer", - "Relation Name": "lineitem_102010", - "Alias": "lineitem" - } - ] - } - } - ] - - ] - } - ] - }, - { - "Plan": { - "Node Type": "Sort", - "Sort Key": ["(sum(((sum(intermediate_column_41_1))::bigint)))::bigint", "intermediate_column_41_0"], - "Plans": [ + "Executor": "Real-Time", + "Job": { + "Task Count": 6, + "Tasks Shown": "One of 6", + "Tasks": [ { - "Node Type": "Aggregate", - "Strategy": "Hashed", - "Parent Relationship": "Outer", - "Group Key": ["intermediate_column_41_0"], - "Plans": [ - { - "Node Type": "Seq Scan", - "Parent Relationship": "Outer", - "Relation Name": "pg_merge_job_0041", - "Alias": "pg_merge_job_0041" - } + "Node": "host=localhost port=57637 dbname=regression", + "Remote Plan": [ + [ + { + "Plan": { + "Node Type": "Aggregate", + "Strategy": "Hashed", + "Group Key": ["l_quantity"], + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "lineitem_102010", + "Alias": "lineitem" + } + ] + } + } + ] + ] } ] - } + }, + "Master Query": [ + { + "Plan": { + "Node Type": "Sort", + "Sort Key": ["(sum(((sum(intermediate_column_41_1))::bigint)))::bigint", "intermediate_column_41_0"], + "Plans": [ + { + "Node Type": "Aggregate", + "Strategy": "Hashed", + "Parent Relationship": "Outer", + "Group Key": ["intermediate_column_41_0"], + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "pg_merge_job_0041", + "Alias": "pg_merge_job_0041" + } + ] + } + ] + } + } + ] } ] +-- Validate JSON format +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); +t -- Test XML format EXPLAIN (COSTS FALSE, FORMAT XML) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; - Real-Time - - 6 - One of 6 - - - host=localhost port=57637 dbname=regression - - - - - Aggregate - Hashed - - l_quantity - - - - Seq Scan - Outer - lineitem_102010 - lineitem - - - - - - - - - - - - Sort - - (sum(((sum(intermediate_column_42_1))::bigint)))::bigint - intermediate_column_42_0 - - + + Real-Time + + 6 + One of 6 + + + host=localhost port=57637 dbname=regression + + + + + Aggregate + Hashed + + l_quantity + + + + Seq Scan + Outer + lineitem_102010 + lineitem + + + + + + + + + + + - Aggregate - Hashed - Outer - - intermediate_column_42_0 - + Sort + + (sum(((sum(intermediate_column_43_1))::bigint)))::bigint + intermediate_column_43_0 + - Seq Scan + Aggregate + Hashed Outer - pg_merge_job_0042 - pg_merge_job_0042 + + intermediate_column_43_0 + + + + Seq Scan + Outer + pg_merge_job_0043 + pg_merge_job_0043 + + - - - + + + +-- Validate XML format +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); +t -- Test YAML format EXPLAIN (COSTS FALSE, FORMAT YAML) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; -Executor: "Real-Time" -- Task Count: 6 - Tasks Shown: "One of 6" - Tasks: - - Node: "host=localhost port=57637 dbname=regression" - Remote Plan: - - Plan: - Node Type: "Aggregate" +- Executor: "Real-Time" + Job: + Task Count: 6 + Tasks Shown: "One of 6" + Tasks: + - Node: "host=localhost port=57637 dbname=regression" + Remote Plan: + - Plan: + Node Type: "Aggregate" + Strategy: "Hashed" + Group Key: + - "l_quantity" + Plans: + - Node Type: "Seq Scan" + Parent Relationship: "Outer" + Relation Name: "lineitem_102010" + Alias: "lineitem" + + Master Query: + - Plan: + Node Type: "Sort" + Sort Key: + - "(sum(((sum(intermediate_column_45_1))::bigint)))::bigint" + - "intermediate_column_45_0" + Plans: + - Node Type: "Aggregate" Strategy: "Hashed" + Parent Relationship: "Outer" Group Key: - - "l_quantity" + - "intermediate_column_45_0" Plans: - Node Type: "Seq Scan" Parent Relationship: "Outer" - Relation Name: "lineitem_102010" - Alias: "lineitem" - -- Plan: - Node Type: "Sort" - Sort Key: - - "(sum(((sum(intermediate_column_43_1))::bigint)))::bigint" - - "intermediate_column_43_0" - Plans: - - Node Type: "Aggregate" - Strategy: "Hashed" - Parent Relationship: "Outer" - Group Key: - - "intermediate_column_43_0" - Plans: - - Node Type: "Seq Scan" - Parent Relationship: "Outer" - Relation Name: "pg_merge_job_0043" - Alias: "pg_merge_job_0043" + Relation Name: "pg_merge_job_0045" + Alias: "pg_merge_job_0045" -- Test Text format EXPLAIN (COSTS FALSE, FORMAT TEXT) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; -Distributed Query into pg_merge_job_0044 +Distributed Query into pg_merge_job_0046 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -197,14 +239,14 @@ Distributed Query into pg_merge_job_0044 -> Seq Scan on lineitem_102010 lineitem Master Query -> Sort - Sort Key: (sum(((sum(intermediate_column_44_1))::bigint)))::bigint, intermediate_column_44_0 + Sort Key: (sum(((sum(intermediate_column_46_1))::bigint)))::bigint, intermediate_column_46_0 -> HashAggregate - Group Key: intermediate_column_44_0 - -> Seq Scan on pg_merge_job_0044 + Group Key: intermediate_column_46_0 + -> Seq Scan on pg_merge_job_0046 -- Test verbose EXPLAIN (COSTS FALSE, VERBOSE TRUE) SELECT sum(l_quantity) / avg(l_quantity) FROM lineitem; -Distributed Query into pg_merge_job_0045 +Distributed Query into pg_merge_job_0047 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -216,15 +258,15 @@ Distributed Query into pg_merge_job_0045 Output: l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment Master Query -> Aggregate - Output: (sum(intermediate_column_45_0) / (sum(intermediate_column_45_1) / sum(intermediate_column_45_2))) - -> Seq Scan on pg_temp_2.pg_merge_job_0045 - Output: intermediate_column_45_0, intermediate_column_45_1, intermediate_column_45_2 + Output: (sum(intermediate_column_47_0) / (sum(intermediate_column_47_1) / sum(intermediate_column_47_2))) + -> Seq Scan on pg_temp_2.pg_merge_job_0047 + Output: intermediate_column_47_0, intermediate_column_47_1, intermediate_column_47_2 -- Test join EXPLAIN (COSTS FALSE) SELECT * FROM lineitem JOIN orders ON l_orderkey = o_orderkey AND l_quantity < 5 ORDER BY l_quantity DESC LIMIT 10; -Distributed Query into pg_merge_job_0046 +Distributed Query into pg_merge_job_0048 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -242,8 +284,8 @@ Distributed Query into pg_merge_job_0046 Master Query -> Limit -> Sort - Sort Key: intermediate_column_46_4 - -> Seq Scan on pg_merge_job_0046 + Sort Key: intermediate_column_48_4 + -> Seq Scan on pg_merge_job_0048 -- Test insert EXPLAIN (COSTS FALSE) INSERT INTO lineitem VALUES(1,0); @@ -291,7 +333,7 @@ Distributed Query -- Test single-shard SELECT EXPLAIN (COSTS FALSE) SELECT l_quantity FROM lineitem WHERE l_orderkey = 5; -Distributed Query into pg_merge_job_0047 +Distributed Query into pg_merge_job_0049 Executor: Router Task Count: 1 Tasks Shown: All @@ -301,11 +343,17 @@ Distributed Query into pg_merge_job_0047 Recheck Cond: (l_orderkey = 5) -> Bitmap Index Scan on lineitem_pkey_102009 Index Cond: (l_orderkey = 5) +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); +t +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); +t -- Test CREATE TABLE ... AS EXPLAIN (COSTS FALSE) CREATE TABLE explain_result AS SELECT * FROM lineitem; -Distributed Query into pg_merge_job_0048 +Distributed Query into pg_merge_job_0052 Executor: Real-Time Task Count: 6 Tasks Shown: One of 6 @@ -313,12 +361,12 @@ Distributed Query into pg_merge_job_0048 Node: host=localhost port=57637 dbname=regression -> Seq Scan on lineitem_102010 lineitem Master Query - -> Seq Scan on pg_merge_job_0048 + -> Seq Scan on pg_merge_job_0052 -- Test all tasks output SET citus.explain_all_tasks TO on; EXPLAIN (COSTS FALSE) SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030; -Distributed Query into pg_merge_job_0049 +Distributed Query into pg_merge_job_0053 Executor: Real-Time Task Count: 3 Tasks Shown: All @@ -339,13 +387,19 @@ Distributed Query into pg_merge_job_0049 Filter: (l_orderkey > 9030) Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0049 + -> Seq Scan on pg_merge_job_0053 +SELECT true AS valid FROM explain_xml($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); +t +SELECT true AS valid FROM explain_json($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); +t -- Test track tracker SET citus.task_executor_type TO 'task-tracker'; SET citus.explain_all_tasks TO off; EXPLAIN (COSTS FALSE) SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030; -Distributed Query into pg_merge_job_0050 +Distributed Query into pg_merge_job_0056 Executor: Task-Tracker Task Count: 3 Tasks Shown: One of 3 @@ -356,7 +410,7 @@ Distributed Query into pg_merge_job_0050 Filter: (l_orderkey > 9030) Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0050 + -> Seq Scan on pg_merge_job_0056 -- Test re-partition join SET citus.large_table_shard_count TO 1; EXPLAIN (COSTS FALSE) @@ -365,7 +419,7 @@ EXPLAIN (COSTS FALSE) WHERE l_orderkey = o_orderkey AND o_custkey = c_custkey AND l_suppkey = s_suppkey; -Distributed Query into pg_merge_job_0053 +Distributed Query into pg_merge_job_0059 Executor: Task-Tracker Task Count: 1 Tasks Shown: None, not supported for re-partition queries @@ -377,4 +431,129 @@ Distributed Query into pg_merge_job_0053 Merge Task Count: 1 Master Query -> Aggregate - -> Seq Scan on pg_merge_job_0053 + -> Seq Scan on pg_merge_job_0059 +EXPLAIN (COSTS FALSE, FORMAT JSON) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; +[ + { + "Executor": "Task-Tracker", + "Job": { + "Task Count": 1, + "Tasks Shown": "None, not supported for re-partition queries", + "Depended Jobs": [ + { + "Map Task Count": 1, + "Merge Task Count": 1, + "Depended Jobs": [ + { + "Map Task Count": 6, + "Merge Task Count": 1 + } + ] + } + ] + }, + "Master Query": [ + { + "Plan": { + "Node Type": "Aggregate", + "Strategy": "Plain", + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Relation Name": "pg_merge_job_0062", + "Alias": "pg_merge_job_0062" + } + ] + } + } + ] + } +] +SELECT true AS valid FROM explain_json($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); +t +EXPLAIN (COSTS FALSE, FORMAT XML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; + + + Task-Tracker + + 1 + None, not supported for re-partition queries + + + 1 + 1 + + + 6 + 1 + + + + + + + + + Aggregate + Plain + + + Seq Scan + Outer + pg_merge_job_0068 + pg_merge_job_0068 + + + + + + + +SELECT true AS valid FROM explain_xml($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); +t +EXPLAIN (COSTS FALSE, FORMAT YAML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; +- Executor: "Task-Tracker" + Job: + Task Count: 1 + Tasks Shown: "None, not supported for re-partition queries" + Depended Jobs: + - Map Task Count: 1 + Merge Task Count: 1 + Depended Jobs: + - Map Task Count: 6 + Merge Task Count: 1 + Master Query: + - Plan: + Node Type: "Aggregate" + Strategy: "Plain" + Plans: + - Node Type: "Seq Scan" + Parent Relationship: "Outer" + Relation Name: "pg_merge_job_0074" + Alias: "pg_merge_job_0074" diff --git a/src/test/regress/sql/multi_explain.sql b/src/test/regress/sql/multi_explain.sql index 143ec3a02..3138a03d7 100644 --- a/src/test/regress/sql/multi_explain.sql +++ b/src/test/regress/sql/multi_explain.sql @@ -7,6 +7,30 @@ SET citus.task_executor_type TO 'real-time'; SET citus.explain_distributed_queries TO on; +-- Function that parses explain output as JSON +CREATE FUNCTION explain_json(query text) +RETURNS jsonb +AS $BODY$ +DECLARE + result jsonb; +BEGIN + EXECUTE format('EXPLAIN (FORMAT JSON) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; + +-- Function that parses explain output as XML +CREATE FUNCTION explain_xml(query text) +RETURNS xml +AS $BODY$ +DECLARE + result xml; +BEGIN + EXECUTE format('EXPLAIN (FORMAT XML) %s', query) INTO result; + RETURN result; +END; +$BODY$ LANGUAGE plpgsql; + -- Test Text format EXPLAIN (COSTS FALSE, FORMAT TEXT) SELECT l_quantity, count(*) count_quantity FROM lineitem @@ -17,11 +41,21 @@ EXPLAIN (COSTS FALSE, FORMAT JSON) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; +-- Validate JSON format +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); + -- Test XML format EXPLAIN (COSTS FALSE, FORMAT XML) SELECT l_quantity, count(*) count_quantity FROM lineitem GROUP BY l_quantity ORDER BY count_quantity, l_quantity; +-- Validate XML format +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity$$); + -- Test YAML format EXPLAIN (COSTS FALSE, FORMAT YAML) SELECT l_quantity, count(*) count_quantity FROM lineitem @@ -61,6 +95,12 @@ EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE) SELECT l_quantity FROM lineitem WHERE l_orderkey = 5; +SELECT true AS valid FROM explain_xml($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); + +SELECT true AS valid FROM explain_json($$ + SELECT l_quantity FROM lineitem WHERE l_orderkey = 5$$); + -- Test CREATE TABLE ... AS EXPLAIN (COSTS FALSE) CREATE TABLE explain_result AS @@ -72,6 +112,12 @@ SET citus.explain_all_tasks TO on; EXPLAIN (COSTS FALSE) SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030; +SELECT true AS valid FROM explain_xml($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); + +SELECT true AS valid FROM explain_json($$ + SELECT avg(l_linenumber) FROM lineitem WHERE l_orderkey > 9030$$); + -- Test track tracker SET citus.task_executor_type TO 'task-tracker'; SET citus.explain_all_tasks TO off; @@ -88,3 +134,38 @@ EXPLAIN (COSTS FALSE) WHERE l_orderkey = o_orderkey AND o_custkey = c_custkey AND l_suppkey = s_suppkey; + +EXPLAIN (COSTS FALSE, FORMAT JSON) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; + +SELECT true AS valid FROM explain_json($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); + +EXPLAIN (COSTS FALSE, FORMAT XML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey; + +SELECT true AS valid FROM explain_xml($$ + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey$$); + +EXPLAIN (COSTS FALSE, FORMAT YAML) + SELECT count(*) + FROM lineitem, orders, customer, supplier + WHERE l_orderkey = o_orderkey + AND o_custkey = c_custkey + AND l_suppkey = s_suppkey;