Speed up RTE walkers

Do it in two ways (a) re-use the rte list as much as possible instead of
re-calculating over and over again (b) Limit the recursion to the relevant
parts of the query tree
pull/2633/head
Marco Slot 2019-03-04 13:45:35 +01:00 committed by Onder Kalaci
parent 5ff1821411
commit ee6a0b6943
4 changed files with 85 additions and 52 deletions

View File

@ -51,7 +51,7 @@ static uint64 NextPlanId = 1;
/* local function forward declarations */ /* local function forward declarations */
static bool NeedsDistributedPlanningWalker(Node *node, void *context); static bool ListContainsDistributedTableRTE(List *rangeTableList);
static PlannedStmt * CreateDistributedPlannedStmt(uint64 planId, PlannedStmt *localPlan, static PlannedStmt * CreateDistributedPlannedStmt(uint64 planId, PlannedStmt *localPlan,
Query *originalQuery, Query *query, Query *originalQuery, Query *query,
ParamListInfo boundParams, ParamListInfo boundParams,
@ -65,9 +65,9 @@ static DistributedPlan * CreateDistributedPlan(uint64 planId, Query *originalQue
static DeferredErrorMessage * DeferErrorIfPartitionTableNotSingleReplicated(Oid static DeferredErrorMessage * DeferErrorIfPartitionTableNotSingleReplicated(Oid
relationId); relationId);
static void AssignRTEIdentities(Query *queryTree); static void AssignRTEIdentities(List *rangeTableList);
static void AssignRTEIdentity(RangeTblEntry *rangeTableEntry, int rteIdentifier); static void AssignRTEIdentity(RangeTblEntry *rangeTableEntry, int rteIdentifier);
static void AdjustPartitioningForDistributedPlanning(Query *parse, static void AdjustPartitioningForDistributedPlanning(List *rangeTableList,
bool setPartitionedTablesInherited); bool setPartitionedTablesInherited);
static PlannedStmt * FinalizePlan(PlannedStmt *localPlan, static PlannedStmt * FinalizePlan(PlannedStmt *localPlan,
DistributedPlan *distributedPlan); DistributedPlan *distributedPlan);
@ -93,15 +93,23 @@ PlannedStmt *
distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
{ {
PlannedStmt *result = NULL; PlannedStmt *result = NULL;
bool needsDistributedPlanning = NeedsDistributedPlanning(parse); bool needsDistributedPlanning = false;
Query *originalQuery = NULL; Query *originalQuery = NULL;
PlannerRestrictionContext *plannerRestrictionContext = NULL; PlannerRestrictionContext *plannerRestrictionContext = NULL;
bool setPartitionedTablesInherited = false; bool setPartitionedTablesInherited = false;
List *rangeTableList = ExtractRangeTableEntryList(parse);
if (cursorOptions & CURSOR_OPT_FORCE_DISTRIBUTED) if (cursorOptions & CURSOR_OPT_FORCE_DISTRIBUTED)
{ {
/* this cursor flag could only be set when Citus has been loaded */
Assert(CitusHasBeenLoaded());
needsDistributedPlanning = true; needsDistributedPlanning = true;
} }
else if (CitusHasBeenLoaded())
{
needsDistributedPlanning = ListContainsDistributedTableRTE(rangeTableList);
}
if (needsDistributedPlanning) if (needsDistributedPlanning)
{ {
@ -127,11 +135,12 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* of the query tree. Note that we copy the query tree once we're sure it's a * of the query tree. Note that we copy the query tree once we're sure it's a
* distributed query. * distributed query.
*/ */
AssignRTEIdentities(parse); AssignRTEIdentities(rangeTableList);
originalQuery = copyObject(parse); originalQuery = copyObject(parse);
setPartitionedTablesInherited = false; setPartitionedTablesInherited = false;
AdjustPartitioningForDistributedPlanning(parse, setPartitionedTablesInherited); AdjustPartitioningForDistributedPlanning(rangeTableList,
setPartitionedTablesInherited);
} }
/* /*
@ -171,7 +180,7 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
boundParams, plannerRestrictionContext); boundParams, plannerRestrictionContext);
setPartitionedTablesInherited = true; setPartitionedTablesInherited = true;
AdjustPartitioningForDistributedPlanning(parse, AdjustPartitioningForDistributedPlanning(rangeTableList,
setPartitionedTablesInherited); setPartitionedTablesInherited);
} }
} }
@ -205,6 +214,22 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
} }
/*
* ExtractRangeTableEntryList is a wrapper around ExtractRangeTableEntryWalker.
* The function traverses the input query and returns all the range table
* entries that are in the query tree.
*/
List *
ExtractRangeTableEntryList(Query *query)
{
List *rangeTblList = NIL;
ExtractRangeTableEntryWalker((Node *) query, &rangeTblList);
return rangeTblList;
}
/* /*
* NeedsDistributedPlanning returns true if the Citus extension is loaded and * NeedsDistributedPlanning returns true if the Citus extension is loaded and
* the query contains a distributed table. * the query contains a distributed table.
@ -216,61 +241,52 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
bool bool
NeedsDistributedPlanning(Query *query) NeedsDistributedPlanning(Query *query)
{ {
List *allRTEs = NIL;
CmdType commandType = query->commandType; CmdType commandType = query->commandType;
if (commandType != CMD_SELECT && commandType != CMD_INSERT &&
commandType != CMD_UPDATE && commandType != CMD_DELETE)
{
return false;
}
if (!CitusHasBeenLoaded()) if (!CitusHasBeenLoaded())
{ {
return false; return false;
} }
if (!NeedsDistributedPlanningWalker((Node *) query, NULL)) if (commandType != CMD_SELECT && commandType != CMD_INSERT &&
commandType != CMD_UPDATE && commandType != CMD_DELETE)
{ {
return false; return false;
} }
return true; ExtractRangeTableEntryWalker((Node *) query, &allRTEs);
return ListContainsDistributedTableRTE(allRTEs);
} }
/* /*
* NeedsDistributedPlanningWalker checks if the query contains any distributed * ListContainsDistributedTableRTE gets a list of range table entries
* tables. * and returns true if there is at least one distributed relation range
* table entry in the list.
*/ */
static bool static bool
NeedsDistributedPlanningWalker(Node *node, void *context) ListContainsDistributedTableRTE(List *rangeTableList)
{ {
if (node == NULL)
{
return false;
}
if (IsA(node, Query))
{
Query *query = (Query *) node;
ListCell *rangeTableCell = NULL; ListCell *rangeTableCell = NULL;
foreach(rangeTableCell, query->rtable) foreach(rangeTableCell, rangeTableList)
{ {
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
Oid relationId = rangeTableEntry->relid; if (rangeTableEntry->rtekind != RTE_RELATION)
if (IsDistributedTable(relationId)) {
continue;
}
if (IsDistributedTable(rangeTableEntry->relid))
{ {
return true; return true;
} }
} }
return query_tree_walker(query, NeedsDistributedPlanningWalker, NULL, 0); return false;
}
else
{
return expression_tree_walker(node, NeedsDistributedPlanningWalker, NULL);
}
} }
@ -283,15 +299,11 @@ NeedsDistributedPlanningWalker(Node *node, void *context)
* our logic. * our logic.
*/ */
static void static void
AssignRTEIdentities(Query *queryTree) AssignRTEIdentities(List *rangeTableList)
{ {
List *rangeTableList = NIL;
ListCell *rangeTableCell = NULL; ListCell *rangeTableCell = NULL;
int rteIdentifier = 1; int rteIdentifier = 1;
/* extract range table entries for simple relations only */
ExtractRangeTableEntryWalker((Node *) queryTree, &rangeTableList);
foreach(rangeTableCell, rangeTableList) foreach(rangeTableCell, rangeTableList)
{ {
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
@ -325,15 +337,11 @@ AssignRTEIdentities(Query *queryTree)
* our logic. * our logic.
*/ */
static void static void
AdjustPartitioningForDistributedPlanning(Query *queryTree, AdjustPartitioningForDistributedPlanning(List *rangeTableList,
bool setPartitionedTablesInherited) bool setPartitionedTablesInherited)
{ {
List *rangeTableList = NIL;
ListCell *rangeTableCell = NULL; ListCell *rangeTableCell = NULL;
/* extract range table entries for simple relations only */
ExtractRangeTableEntryWalker((Node *) queryTree, &rangeTableList);
foreach(rangeTableCell, rangeTableList) foreach(rangeTableCell, rangeTableList)
{ {
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
@ -344,7 +352,8 @@ AdjustPartitioningForDistributedPlanning(Query *queryTree,
* we set each distributed partitioned table's inh flag to appropriate * we set each distributed partitioned table's inh flag to appropriate
* value before and after dropping to the standart_planner. * value before and after dropping to the standart_planner.
*/ */
if (IsDistributedTable(rangeTableEntry->relid) && if (rangeTableEntry->rtekind == RTE_RELATION &&
IsDistributedTable(rangeTableEntry->relid) &&
PartitionedTable(rangeTableEntry->relid)) PartitionedTable(rangeTableEntry->relid))
{ {
rangeTableEntry->inh = setPartitionedTablesInherited; rangeTableEntry->inh = setPartitionedTablesInherited;
@ -724,7 +733,8 @@ CreateDistributedPlan(uint64 planId, Query *originalQuery, Query *query, ParamLi
* distributed_planner, but on a copy of the original query, so we need * distributed_planner, but on a copy of the original query, so we need
* to do it again here. * to do it again here.
*/ */
AdjustPartitioningForDistributedPlanning(newQuery, setPartitionedTablesInherited); AdjustPartitioningForDistributedPlanning(ExtractRangeTableEntryList(newQuery),
setPartitionedTablesInherited);
/* /*
* Some relations may have been removed from the query, but we can skip * Some relations may have been removed from the query, but we can skip

View File

@ -2026,9 +2026,30 @@ ExtractRangeTableEntryWalker(Node *node, List **rangeTableList)
} }
else if (IsA(node, Query)) else if (IsA(node, Query))
{ {
Query *query = (Query *) node;
/*
* Since we're only interested in range table entries, we only descend
* into all parts of the query when it is necessary. Otherwise, it is
* sufficient to descend into range table list since its the only part
* of the query that could contain range table entries.
*/
if (query->hasSubLinks || query->cteList || query->setOperations)
{
/* descend into all parts of the query */
walkIsComplete = query_tree_walker((Query *) node, walkIsComplete = query_tree_walker((Query *) node,
ExtractRangeTableEntryWalker, ExtractRangeTableEntryWalker,
rangeTableList, QTW_EXAMINE_RTES); rangeTableList,
QTW_EXAMINE_RTES);
}
else
{
/* descend only into RTEs */
walkIsComplete = range_table_walker(query->rtable,
ExtractRangeTableEntryWalker,
rangeTableList,
QTW_EXAMINE_RTES);
}
} }
else else
{ {

View File

@ -1505,6 +1505,7 @@ SubqueryPushdownMultiNodeTree(Query *queryTree)
pushedDownQuery->rtable = copyObject(queryTree->rtable); pushedDownQuery->rtable = copyObject(queryTree->rtable);
pushedDownQuery->setOperations = copyObject(queryTree->setOperations); pushedDownQuery->setOperations = copyObject(queryTree->setOperations);
pushedDownQuery->querySource = queryTree->querySource; pushedDownQuery->querySource = queryTree->querySource;
pushedDownQuery->hasSubLinks = queryTree->hasSubLinks;
subqueryNode = MultiSubqueryPushdownTable(pushedDownQuery); subqueryNode = MultiSubqueryPushdownTable(pushedDownQuery);

View File

@ -83,6 +83,7 @@ typedef struct RelationRowLock
extern PlannedStmt * distributed_planner(Query *parse, int cursorOptions, extern PlannedStmt * distributed_planner(Query *parse, int cursorOptions,
ParamListInfo boundParams); ParamListInfo boundParams);
extern List * ExtractRangeTableEntryList(Query *query);
extern bool NeedsDistributedPlanning(Query *query); extern bool NeedsDistributedPlanning(Query *query);
extern struct DistributedPlan * GetDistributedPlan(CustomScan *node); extern struct DistributedPlan * GetDistributedPlan(CustomScan *node);
extern void multi_relation_restriction_hook(PlannerInfo *root, RelOptInfo *relOptInfo, extern void multi_relation_restriction_hook(PlannerInfo *root, RelOptInfo *relOptInfo,