mirror of https://github.com/citusdata/citus.git
recursively plan right side if constant false join clause exists between 2 nonrecurring parts
parent
4f84259c2a
commit
29f4b18156
|
@ -1208,6 +1208,19 @@ static JoinOrderNode *
|
||||||
CartesianProductReferenceJoin(JoinOrderNode *currentJoinNode, TableEntry *candidateTable,
|
CartesianProductReferenceJoin(JoinOrderNode *currentJoinNode, TableEntry *candidateTable,
|
||||||
List *applicableJoinClauses, JoinType joinType)
|
List *applicableJoinClauses, JoinType joinType)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* right distributed part is already recursively planned.
|
||||||
|
* constant false join is supported as CartesianProductReferenceJoin.
|
||||||
|
*/
|
||||||
|
if (list_length(applicableJoinClauses) == 1 &&
|
||||||
|
ContainsFalseClause(applicableJoinClauses))
|
||||||
|
{
|
||||||
|
return MakeJoinOrderNode(candidateTable, CARTESIAN_PRODUCT_REFERENCE_JOIN,
|
||||||
|
currentJoinNode->partitionColumnList,
|
||||||
|
currentJoinNode->partitionMethod,
|
||||||
|
currentJoinNode->anchorTable, joinType);
|
||||||
|
}
|
||||||
|
|
||||||
bool leftIsReferenceTable = IsCitusTableType(
|
bool leftIsReferenceTable = IsCitusTableType(
|
||||||
currentJoinNode->tableEntry->relationId,
|
currentJoinNode->tableEntry->relationId,
|
||||||
REFERENCE_TABLE);
|
REFERENCE_TABLE);
|
||||||
|
|
|
@ -152,6 +152,8 @@ static void RecursivelyPlanNonColocatedSubqueriesInWhere(Query *query,
|
||||||
recursivePlanningContext);
|
recursivePlanningContext);
|
||||||
static bool RecursivelyPlanRecurringTupleOuterJoinWalker(Node *node, Query *query,
|
static bool RecursivelyPlanRecurringTupleOuterJoinWalker(Node *node, Query *query,
|
||||||
RecursivePlanningContext *context);
|
RecursivePlanningContext *context);
|
||||||
|
static bool RecursivelyPlanConstantFalseJoinsWalker(Node *node, Query *query,
|
||||||
|
RecursivePlanningContext *context);
|
||||||
static void RecursivelyPlanDistributedJoinNode(Node *node, Query *query,
|
static void RecursivelyPlanDistributedJoinNode(Node *node, Query *query,
|
||||||
RecursivePlanningContext *context);
|
RecursivePlanningContext *context);
|
||||||
static bool IsRTERefRecurring(RangeTblRef *rangeTableRef, Query *query);
|
static bool IsRTERefRecurring(RangeTblRef *rangeTableRef, Query *query);
|
||||||
|
@ -383,10 +385,107 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context
|
||||||
RecursivelyPlanAllSubqueries((Node *) query->targetList, context);
|
RecursivelyPlanAllSubqueries((Node *) query->targetList, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make right side recurring when query has constant false join
|
||||||
|
* with both side distributed
|
||||||
|
*/
|
||||||
|
RecursivelyPlanConstantFalseJoinsWalker((Node *) query->jointree,
|
||||||
|
query, context);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RecursivelyPlanConstantFalseJoinsWalker replaces right side of the joins with constant
|
||||||
|
* false clause.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* SELECT dist [FULL/LEFT/RIGHT/INNER] JOIN dist ON (false)
|
||||||
|
* is converted to
|
||||||
|
* SELECT dist [FULL/LEFT/RIGHT/INNER] JOIN intermediate_result ON (false)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
RecursivelyPlanConstantFalseJoinsWalker(Node *node, Query *query,
|
||||||
|
RecursivePlanningContext *context)
|
||||||
|
{
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (IsA(node, FromExpr))
|
||||||
|
{
|
||||||
|
FromExpr *fromExpr = (FromExpr *) node;
|
||||||
|
ListCell *fromExprCell;
|
||||||
|
|
||||||
|
/* search for join trees in each FROM element */
|
||||||
|
foreach(fromExprCell, fromExpr->fromlist)
|
||||||
|
{
|
||||||
|
Node *fromElement = (Node *) lfirst(fromExprCell);
|
||||||
|
|
||||||
|
RecursivelyPlanConstantFalseJoinsWalker(fromElement, query,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (IsA(node, JoinExpr))
|
||||||
|
{
|
||||||
|
JoinExpr *joinExpr = (JoinExpr *) node;
|
||||||
|
|
||||||
|
Node *leftNode = joinExpr->larg;
|
||||||
|
Node *rightNode = joinExpr->rarg;
|
||||||
|
Node *joinQualsNode = joinExpr->quals;
|
||||||
|
List *joinQualList = NIL;
|
||||||
|
|
||||||
|
if (joinQualsNode == NULL)
|
||||||
|
{
|
||||||
|
joinQualList = NIL;
|
||||||
|
}
|
||||||
|
else if (IsA(joinQualsNode, List))
|
||||||
|
{
|
||||||
|
joinQualList = (List *) joinQualsNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* this part of code only run for subqueries */
|
||||||
|
Node *joinClause = eval_const_expressions(NULL, joinQualsNode);
|
||||||
|
joinClause = (Node *) canonicalize_qual((Expr *) joinClause, false);
|
||||||
|
joinQualList = make_ands_implicit((Expr *) joinClause);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasConstantFalseJoin = ContainsFalseClause(joinQualList);
|
||||||
|
|
||||||
|
bool isLeftRefRecurring = RecursivelyPlanConstantFalseJoinsWalker(leftNode, query,
|
||||||
|
context);
|
||||||
|
bool isRightRefRecurring = RecursivelyPlanConstantFalseJoinsWalker(rightNode,
|
||||||
|
query,
|
||||||
|
context);
|
||||||
|
|
||||||
|
if (!isLeftRefRecurring && !isRightRefRecurring && hasConstantFalseJoin)
|
||||||
|
{
|
||||||
|
ereport(DEBUG1, (errmsg("recursively planning right side of "
|
||||||
|
"the constant false join")));
|
||||||
|
RecursivelyPlanDistributedJoinNode(rightNode, query,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isLeftRefRecurring || isRightRefRecurring;
|
||||||
|
}
|
||||||
|
else if (IsA(node, RangeTblRef))
|
||||||
|
{
|
||||||
|
RangeTblRef *rangeTableRef = castNode(RangeTblRef, node);
|
||||||
|
return IsRTERefRecurring(rangeTableRef, query);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ereport(ERROR, errmsg("got unexpected node type (%d) when recursively "
|
||||||
|
"planning a constant false join",
|
||||||
|
nodeTag(node)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetPlannerRestrictionContext returns the planner restriction context
|
* GetPlannerRestrictionContext returns the planner restriction context
|
||||||
* from the given context.
|
* from the given context.
|
||||||
|
|
|
@ -520,12 +520,27 @@ SELECT
|
||||||
FROM
|
FROM
|
||||||
orders INNER JOIN customer_append ON (o_custkey = c_custkey AND false);
|
orders INNER JOIN customer_append ON (o_custkey = c_custkey AND false);
|
||||||
DEBUG: Router planner does not support append-partitioned tables.
|
DEBUG: Router planner does not support append-partitioned tables.
|
||||||
QUERY PLAN
|
DEBUG: recursively planning right side of the constant false join
|
||||||
|
DEBUG: recursively planning distributed relation "customer_append" since it is part of a distributed join node that is outer joined with a recurring rel
|
||||||
|
DEBUG: Wrapping relation "customer_append" to a subquery
|
||||||
|
DEBUG: Router planner does not support append-partitioned tables.
|
||||||
|
DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM public.customer_append WHERE false
|
||||||
|
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT orders.o_orderkey FROM (public.orders JOIN (SELECT NULL::integer AS c_custkey, NULL::character varying(25) AS c_name, NULL::character varying(40) AS c_address, NULL::integer AS c_nationkey, NULL::character(15) AS c_phone, NULL::numeric(15,2) AS c_acctbal, NULL::character(10) AS c_mktsegment, NULL::character varying(117) AS c_comment FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) customer_append_1) customer_append ON (((orders.o_custkey OPERATOR(pg_catalog.=) customer_append.c_custkey) AND false)))
|
||||||
|
DEBUG: Creating router plan
|
||||||
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Custom Scan (Citus Adaptive)
|
Custom Scan (Citus Adaptive)
|
||||||
Task Count: 0
|
-> Distributed Subplan XXX_1
|
||||||
|
-> Custom Scan (Citus Adaptive)
|
||||||
|
Task Count: 0
|
||||||
|
Tasks Shown: All
|
||||||
|
Task Count: 1
|
||||||
Tasks Shown: All
|
Tasks Shown: All
|
||||||
(3 rows)
|
-> Task
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Result
|
||||||
|
One-Time Filter: false
|
||||||
|
(11 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -1134,7 +1134,9 @@ SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) WHERE dist1.x >2 ORDE
|
||||||
--- constant false filter as join filter for left join.
|
--- constant false filter as join filter for left join.
|
||||||
-- inner table will be converted to empty result. Constant filter will be applied before join but will not be pushdowned.
|
-- inner table will be converted to empty result. Constant filter will be applied before join but will not be pushdowned.
|
||||||
SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4;
|
SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4;
|
||||||
LOG: join order: [ "dist1" ][ cartesian product(LEFT) "dist2" ]
|
LOG: join order: [ "dist2" ]
|
||||||
|
x | y | x | y
|
||||||
|
---------------------------------------------------------------------
|
||||||
1 | 2 | |
|
1 | 2 | |
|
||||||
3 | 4 | |
|
3 | 4 | |
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
|
@ -1123,6 +1123,8 @@ FROM
|
||||||
correlated_subquery_view
|
correlated_subquery_view
|
||||||
LEFT JOIN LATERAL
|
LEFT JOIN LATERAL
|
||||||
(SELECT max(value_2) as mx FROM events_table WHERE correlated_subquery_view.user_id = events_table.user_id) as foo ON (false);
|
(SELECT max(value_2) as mx FROM events_table WHERE correlated_subquery_view.user_id = events_table.user_id) as foo ON (false);
|
||||||
|
DEBUG: recursively planning right side of the constant false join
|
||||||
|
DEBUG: recursively planning the distributed subquery since it is part of a distributed join node that is outer joined with a recurring rel
|
||||||
sum
|
sum
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue