Add infrastructure for detecting non-colocated subqueries

pull/2016/head
Onder Kalaci 2018-02-15 15:04:52 +02:00
parent cdb8d429a7
commit 7b57e0562a
3 changed files with 75 additions and 2 deletions

View File

@ -158,7 +158,6 @@ static MultiNode * SubqueryMultiNodeTree(Query *originalQuery,
Query *queryTree, Query *queryTree,
PlannerRestrictionContext * PlannerRestrictionContext *
plannerRestrictionContext); plannerRestrictionContext);
static List * SublinkList(Query *originalQuery);
static bool ExtractSublinkWalker(Node *node, List **sublinkList); static bool ExtractSublinkWalker(Node *node, List **sublinkList);
static MultiNode * SubqueryPushdownMultiNodeTree(Query *queryTree); static MultiNode * SubqueryPushdownMultiNodeTree(Query *queryTree);
@ -316,7 +315,7 @@ FindNodeCheck(Node *node, bool (*check)(Node *))
* that the function should be called on the original query given that postgres * that the function should be called on the original query given that postgres
* standard_planner() may convert the subqueries in WHERE clause to joins. * standard_planner() may convert the subqueries in WHERE clause to joins.
*/ */
static List * List *
SublinkList(Query *originalQuery) SublinkList(Query *originalQuery)
{ {
FromExpr *joinTree = originalQuery->jointree; FromExpr *joinTree = originalQuery->jointree;

View File

@ -116,6 +116,12 @@ typedef struct VarLevelsUpWalkerContext
static DeferredErrorMessage * RecursivelyPlanSubqueriesAndCTEs(Query *query, static DeferredErrorMessage * RecursivelyPlanSubqueriesAndCTEs(Query *query,
RecursivePlanningContext * RecursivePlanningContext *
context); context);
static bool ShouldRecursivelyPlanNonColocatedSubqueries(Query *subquery,
RecursivePlanningContext *
context);
static void RecursivelyPlanNonColocatedSubqueries(Query *subquery,
RecursivePlanningContext *context);
static bool ShouldRecursivelyPlanAllSubqueriesInWhere(Query *query); static bool ShouldRecursivelyPlanAllSubqueriesInWhere(Query *query);
static bool RecursivelyPlanAllSubqueries(Node *node, static bool RecursivelyPlanAllSubqueries(Node *node,
RecursivePlanningContext *planningContext); RecursivePlanningContext *planningContext);
@ -272,10 +278,77 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context
RecursivelyPlanAllSubqueries((Node *) query->jointree->quals, context); RecursivelyPlanAllSubqueries((Node *) query->jointree->quals, context);
} }
if (ShouldRecursivelyPlanNonColocatedSubqueries(query, context))
{
RecursivelyPlanNonColocatedSubqueries(query, context);
}
return NULL; return NULL;
} }
/*
* ShouldRecursivelyPlanNonColocatedSubqueries returns true if the input query contains joins
* that are not on the distribution key.
* *
* Note that at the point that this function is called, we've already recursively planned all
* the leaf subqueries. Thus, we're actually checking whether the joins among the subqueries
* on the distribution key or not.
*/
static bool
ShouldRecursivelyPlanNonColocatedSubqueries(Query *subquery,
RecursivePlanningContext *context)
{
/* if the input query already contains the equality, simply return */
if (context->queryContainsDistributionKeyEquality)
{
return false;
}
/*
* This check helps us in two ways:
* (i) We're not targeting queries that don't include subqueries at all,
* they should go through regular planning.
* (ii) Lower level subqueries are already recursively planned, so we should
* only bother non-colocated subquery joins, which only happens when
* there are subqueries.
*/
if (SubqueryEntryList(subquery) == NIL && SublinkList(subquery) == NIL)
{
return false;
}
/*
* At this point, we might be recursively planning a a subquery which will be pulled
* by PostgreSQL standard_planner (i.e., tpch_7_nested). However, checking for those
* cases are pretty complicated and, seems not super useful thing to implement.
*/
/* direct joins with local tables are not supported by any of Citus planners */
if (FindNodeCheckInRangeTableList(subquery->rtable, IsLocalTableRTE))
{
return false;
}
/*
* Finally, check whether this subquery contains distribution key equality or not.
*/
if (!SubqueryContainsDistributionKeyEquality(subquery,
context->plannerRestrictionContext))
{
return true;
}
return false;
}
static void
RecursivelyPlanNonColocatedSubqueries(Query *query, RecursivePlanningContext *context)
{ }
/* /*
* ShouldRecursivelyPlanAllSubqueriesInWhere returns true if the query has * ShouldRecursivelyPlanAllSubqueriesInWhere returns true if the query has
* a WHERE clause and a recurring FROM clause (does not contain a distributed * a WHERE clause and a recurring FROM clause (does not contain a distributed

View File

@ -187,6 +187,7 @@ extern bool SubqueryPushdown;
extern MultiTreeRoot * MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree, extern MultiTreeRoot * MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree,
PlannerRestrictionContext * PlannerRestrictionContext *
plannerRestrictionContext); plannerRestrictionContext);
extern List * SublinkList(Query *originalQuery);
extern bool SingleRelationRepartitionSubquery(Query *queryTree); extern bool SingleRelationRepartitionSubquery(Query *queryTree);
extern DeferredErrorMessage * DeferErrorIfCannotPushdownSubquery(Query *subqueryTree, extern DeferredErrorMessage * DeferErrorIfCannotPushdownSubquery(Query *subqueryTree,
bool bool