mirror of https://github.com/citusdata/citus.git
Merge pull request #1888 from citusdata/subplan_explain
Show distributed subplan ID in EXPLAIN outputpull/1883/head
commit
393e625cb2
|
@ -72,7 +72,7 @@ typedef struct RemoteExplainPlan
|
||||||
|
|
||||||
|
|
||||||
/* Explain functions for distributed queries */
|
/* Explain functions for distributed queries */
|
||||||
static void ExplainSubPlans(List *subPlanList, ExplainState *es);
|
static void ExplainSubPlans(DistributedPlan *distributedPlan, ExplainState *es);
|
||||||
static void ExplainJob(Job *job, ExplainState *es);
|
static void ExplainJob(Job *job, ExplainState *es);
|
||||||
static void ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es);
|
static void ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es);
|
||||||
static void ExplainTaskList(List *taskList, ExplainState *es);
|
static void ExplainTaskList(List *taskList, ExplainState *es);
|
||||||
|
@ -127,7 +127,7 @@ CitusExplainScan(CustomScanState *node, List *ancestors, struct ExplainState *es
|
||||||
|
|
||||||
if (distributedPlan->subPlanList != NIL)
|
if (distributedPlan->subPlanList != NIL)
|
||||||
{
|
{
|
||||||
ExplainSubPlans(distributedPlan->subPlanList, es);
|
ExplainSubPlans(distributedPlan, es);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplainJob(distributedPlan->workerJob, es);
|
ExplainJob(distributedPlan->workerJob, es);
|
||||||
|
@ -179,20 +179,14 @@ CoordinatorInsertSelectExplainScan(CustomScanState *node, List *ancestors,
|
||||||
* planning time and set it to 0.
|
* planning time and set it to 0.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ExplainSubPlans(List *subPlanList, ExplainState *es)
|
ExplainSubPlans(DistributedPlan *distributedPlan, ExplainState *es)
|
||||||
{
|
{
|
||||||
ListCell *subPlanCell = NULL;
|
ListCell *subPlanCell = NULL;
|
||||||
|
uint64 planId = distributedPlan->planId;
|
||||||
|
|
||||||
ExplainOpenGroup("Subplans", "Subplans", false, es);
|
ExplainOpenGroup("Subplans", "Subplans", false, es);
|
||||||
|
|
||||||
if (es->format == EXPLAIN_FORMAT_TEXT)
|
foreach(subPlanCell, distributedPlan->subPlanList)
|
||||||
{
|
|
||||||
appendStringInfoSpaces(es->str, es->indent * 2);
|
|
||||||
appendStringInfo(es->str, "-> Distributed Subplan\n");
|
|
||||||
es->indent += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(subPlanCell, subPlanList)
|
|
||||||
{
|
{
|
||||||
DistributedSubPlan *subPlan = (DistributedSubPlan *) lfirst(subPlanCell);
|
DistributedSubPlan *subPlan = (DistributedSubPlan *) lfirst(subPlanCell);
|
||||||
PlannedStmt *plan = subPlan->plan;
|
PlannedStmt *plan = subPlan->plan;
|
||||||
|
@ -201,6 +195,15 @@ ExplainSubPlans(List *subPlanList, ExplainState *es)
|
||||||
char *queryString = NULL;
|
char *queryString = NULL;
|
||||||
instr_time planduration;
|
instr_time planduration;
|
||||||
|
|
||||||
|
if (es->format == EXPLAIN_FORMAT_TEXT)
|
||||||
|
{
|
||||||
|
char *resultId = GenerateResultId(planId, subPlan->subPlanId);
|
||||||
|
|
||||||
|
appendStringInfoSpaces(es->str, es->indent * 2);
|
||||||
|
appendStringInfo(es->str, "-> Distributed Subplan %s\n", resultId);
|
||||||
|
es->indent += 3;
|
||||||
|
}
|
||||||
|
|
||||||
/* set the planning time to 0 */
|
/* set the planning time to 0 */
|
||||||
INSTR_TIME_SET_CURRENT(planduration);
|
INSTR_TIME_SET_CURRENT(planduration);
|
||||||
INSTR_TIME_SUBTRACT(planduration, planduration);
|
INSTR_TIME_SUBTRACT(planduration, planduration);
|
||||||
|
@ -210,12 +213,12 @@ ExplainSubPlans(List *subPlanList, ExplainState *es)
|
||||||
#else
|
#else
|
||||||
ExplainOnePlan(plan, into, es, queryString, params, &planduration);
|
ExplainOnePlan(plan, into, es, queryString, params, &planduration);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
if (es->format == EXPLAIN_FORMAT_TEXT)
|
if (es->format == EXPLAIN_FORMAT_TEXT)
|
||||||
{
|
{
|
||||||
es->indent -= 3;
|
es->indent -= 3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ExplainCloseGroup("Subplans", "Subplans", false, es);
|
ExplainCloseGroup("Subplans", "Subplans", false, es);
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,17 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query,
|
||||||
DeferredErrorMessage *error = NULL;
|
DeferredErrorMessage *error = NULL;
|
||||||
RecursivePlanningContext context;
|
RecursivePlanningContext context;
|
||||||
|
|
||||||
|
context.level = 0;
|
||||||
|
context.planId = planId;
|
||||||
|
context.subPlanList = NIL;
|
||||||
|
context.plannerRestrictionContext = plannerRestrictionContext;
|
||||||
|
|
||||||
|
error = RecursivelyPlanCTEs(query, &context);
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
if (SubqueryPushdown)
|
if (SubqueryPushdown)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -155,17 +166,6 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.level = 0;
|
|
||||||
context.planId = planId;
|
|
||||||
context.subPlanList = NIL;
|
|
||||||
context.plannerRestrictionContext = plannerRestrictionContext;
|
|
||||||
|
|
||||||
error = RecursivelyPlanCTEs(query, &context);
|
|
||||||
if (error != NULL)
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: plan subqueries */
|
/* XXX: plan subqueries */
|
||||||
|
|
||||||
*subPlanList = context.subPlanList;
|
*subPlanList = context.subPlanList;
|
||||||
|
|
|
@ -713,6 +713,7 @@ Limit
|
||||||
Sort Key: events.event_time DESC
|
Sort Key: events.event_time DESC
|
||||||
-> Seq Scan on events_1400029 events
|
-> Seq Scan on events_1400029 events
|
||||||
Filter: (composite_id = users.composite_id)
|
Filter: (composite_id = users.composite_id)
|
||||||
|
RESET citus.subquery_pushdown;
|
||||||
-- Test all tasks output
|
-- Test all tasks output
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
EXPLAIN (COSTS FALSE)
|
EXPLAIN (COSTS FALSE)
|
||||||
|
@ -1115,3 +1116,75 @@ Custom Scan (Citus INSERT ... SELECT via coordinator)
|
||||||
-> Append
|
-> Append
|
||||||
-> Function Scan on generate_series s
|
-> Function Scan on generate_series s
|
||||||
-> Function Scan on generate_series s_1
|
-> Function Scan on generate_series s_1
|
||||||
|
-- explain with recursive planning
|
||||||
|
EXPLAIN (COSTS OFF, VERBOSE true)
|
||||||
|
WITH keys AS (
|
||||||
|
SELECT DISTINCT l_orderkey FROM lineitem_hash_part
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey)
|
||||||
|
ORDER BY s;
|
||||||
|
Custom Scan (Citus Router)
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
-> Distributed Subplan 54_1
|
||||||
|
-> HashAggregate
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
Group Key: remote_scan.l_orderkey
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> HashAggregate
|
||||||
|
Output: l_orderkey
|
||||||
|
Group Key: lineitem_hash_part.l_orderkey
|
||||||
|
-> Seq Scan on public.lineitem_hash_part_360038 lineitem_hash_part
|
||||||
|
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
|
||||||
|
-> Distributed Subplan 54_2
|
||||||
|
-> Function Scan on pg_catalog.generate_series s
|
||||||
|
Output: s
|
||||||
|
Function Call: generate_series(1, 10)
|
||||||
|
Task Count: 1
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Merge Join
|
||||||
|
Output: intermediate_result_1.l_orderkey, intermediate_result.s
|
||||||
|
Merge Cond: (intermediate_result.s = intermediate_result_1.l_orderkey)
|
||||||
|
-> Sort
|
||||||
|
Output: intermediate_result.s
|
||||||
|
Sort Key: intermediate_result.s
|
||||||
|
-> Function Scan on pg_catalog.read_intermediate_result intermediate_result
|
||||||
|
Output: intermediate_result.s
|
||||||
|
Function Call: read_intermediate_result('54_2'::text, 'binary'::citus_copy_format)
|
||||||
|
-> Sort
|
||||||
|
Output: intermediate_result_1.l_orderkey
|
||||||
|
Sort Key: intermediate_result_1.l_orderkey
|
||||||
|
-> Function Scan on pg_catalog.read_intermediate_result intermediate_result_1
|
||||||
|
Output: intermediate_result_1.l_orderkey
|
||||||
|
Function Call: read_intermediate_result('54_1'::text, 'binary'::citus_copy_format)
|
||||||
|
SELECT true AS valid FROM explain_json($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
t
|
||||||
|
SELECT true AS valid FROM explain_xml($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
t
|
||||||
|
|
|
@ -713,6 +713,7 @@ Limit
|
||||||
Sort Key: events.event_time DESC
|
Sort Key: events.event_time DESC
|
||||||
-> Seq Scan on events_1400029 events
|
-> Seq Scan on events_1400029 events
|
||||||
Filter: (composite_id = users.composite_id)
|
Filter: (composite_id = users.composite_id)
|
||||||
|
RESET citus.subquery_pushdown;
|
||||||
-- Test all tasks output
|
-- Test all tasks output
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
EXPLAIN (COSTS FALSE)
|
EXPLAIN (COSTS FALSE)
|
||||||
|
@ -1115,3 +1116,75 @@ Custom Scan (Citus INSERT ... SELECT via coordinator)
|
||||||
-> Append
|
-> Append
|
||||||
-> Function Scan on generate_series s
|
-> Function Scan on generate_series s
|
||||||
-> Function Scan on generate_series s_1
|
-> Function Scan on generate_series s_1
|
||||||
|
-- explain with recursive planning
|
||||||
|
EXPLAIN (COSTS OFF, VERBOSE true)
|
||||||
|
WITH keys AS (
|
||||||
|
SELECT DISTINCT l_orderkey FROM lineitem_hash_part
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey)
|
||||||
|
ORDER BY s;
|
||||||
|
Custom Scan (Citus Router)
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
-> Distributed Subplan 54_1
|
||||||
|
-> HashAggregate
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
Group Key: remote_scan.l_orderkey
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Output: remote_scan.l_orderkey
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> HashAggregate
|
||||||
|
Output: l_orderkey
|
||||||
|
Group Key: lineitem_hash_part.l_orderkey
|
||||||
|
-> Seq Scan on public.lineitem_hash_part_360038 lineitem_hash_part
|
||||||
|
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
|
||||||
|
-> Distributed Subplan 54_2
|
||||||
|
-> Function Scan on pg_catalog.generate_series s
|
||||||
|
Output: s
|
||||||
|
Function Call: generate_series(1, 10)
|
||||||
|
Task Count: 1
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Merge Join
|
||||||
|
Output: intermediate_result_1.l_orderkey, intermediate_result.s
|
||||||
|
Merge Cond: (intermediate_result.s = intermediate_result_1.l_orderkey)
|
||||||
|
-> Sort
|
||||||
|
Output: intermediate_result.s
|
||||||
|
Sort Key: intermediate_result.s
|
||||||
|
-> Function Scan on pg_catalog.read_intermediate_result intermediate_result
|
||||||
|
Output: intermediate_result.s
|
||||||
|
Function Call: read_intermediate_result('54_2'::text, 'binary'::citus_copy_format)
|
||||||
|
-> Sort
|
||||||
|
Output: intermediate_result_1.l_orderkey
|
||||||
|
Sort Key: intermediate_result_1.l_orderkey
|
||||||
|
-> Function Scan on pg_catalog.read_intermediate_result intermediate_result_1
|
||||||
|
Output: intermediate_result_1.l_orderkey
|
||||||
|
Function Call: read_intermediate_result('54_1'::text, 'binary'::citus_copy_format)
|
||||||
|
SELECT true AS valid FROM explain_json($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
t
|
||||||
|
SELECT true AS valid FROM explain_xml($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
t
|
||||||
|
|
|
@ -356,6 +356,8 @@ ORDER BY
|
||||||
LIMIT
|
LIMIT
|
||||||
10;
|
10;
|
||||||
|
|
||||||
|
RESET citus.subquery_pushdown;
|
||||||
|
|
||||||
-- Test all tasks output
|
-- Test all tasks output
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
|
|
||||||
|
@ -519,3 +521,36 @@ EXPLAIN (COSTS OFF)
|
||||||
INSERT INTO lineitem_hash_part
|
INSERT INTO lineitem_hash_part
|
||||||
( SELECT s FROM generate_series(1,5) s) UNION
|
( SELECT s FROM generate_series(1,5) s) UNION
|
||||||
( SELECT s FROM generate_series(5,10) s);
|
( SELECT s FROM generate_series(5,10) s);
|
||||||
|
|
||||||
|
-- explain with recursive planning
|
||||||
|
EXPLAIN (COSTS OFF, VERBOSE true)
|
||||||
|
WITH keys AS (
|
||||||
|
SELECT DISTINCT l_orderkey FROM lineitem_hash_part
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey)
|
||||||
|
ORDER BY s;
|
||||||
|
|
||||||
|
SELECT true AS valid FROM explain_json($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
|
||||||
|
SELECT true AS valid FROM explain_xml($$
|
||||||
|
WITH result AS (
|
||||||
|
SELECT l_quantity, count(*) count_quantity FROM lineitem
|
||||||
|
GROUP BY l_quantity ORDER BY count_quantity, l_quantity
|
||||||
|
),
|
||||||
|
series AS (
|
||||||
|
SELECT s FROM generate_series(1,10) s
|
||||||
|
)
|
||||||
|
SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey)
|
||||||
|
$$);
|
||||||
|
|
Loading…
Reference in New Issue