diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-04-07 17:54:31 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-04-07 17:54:39 -0300 |
commit | 499be013de65242235ebdde06adb08db887f0ea5 (patch) | |
tree | c1f69b818f917379fb4f72e80535fef899a40b5b /src/backend/commands/explain.c | |
parent | 5c0675215e153ba1297fd494b34af2fdebd645d1 (diff) | |
download | postgresql-499be013de65242235ebdde06adb08db887f0ea5.tar.gz postgresql-499be013de65242235ebdde06adb08db887f0ea5.zip |
Support partition pruning at execution time
Existing partition pruning is only able to work at plan time, for query
quals that appear in the parsed query. This is good but limiting, as
there can be parameters that appear later that can be usefully used to
further prune partitions.
This commit adds support for pruning subnodes of Append which cannot
possibly contain any matching tuples, during execution, by evaluating
Params to determine the minimum set of subnodes that can possibly match.
We support more than just simple Params in WHERE clauses. Support
additionally includes:
1. Parameterized Nested Loop Joins: The parameter from the outer side of the
join can be used to determine the minimum set of inner side partitions to
scan.
2. Initplans: Once an initplan has been executed we can then determine which
partitions match the value from the initplan.
Partition pruning is performed in two ways. When Params external to the plan
are found to match the partition key we attempt to prune away unneeded Append
subplans during the initialization of the executor. This allows us to bypass
the initialization of non-matching subplans meaning they won't appear in the
EXPLAIN or EXPLAIN ANALYZE output.
For parameters whose value is only known during the actual execution
then the pruning of these subplans must wait. Subplans which are
eliminated during this stage of pruning are still visible in the EXPLAIN
output. In order to determine if pruning has actually taken place, the
EXPLAIN ANALYZE must be viewed. If a certain Append subplan was never
executed due to the elimination of the partition then the execution
timing area will state "(never executed)". Whereas, if, for example in
the case of parameterized nested loops, the number of loops stated in
the EXPLAIN ANALYZE output for certain subplans may appear lower than
others due to the subplan having been scanned fewer times. This is due
to the list of matching subnodes having to be evaluated whenever a
parameter which was found to match the partition key changes.
This commit required some additional infrastructure that permits the
building of a data structure which is able to perform the translation of
the matching partition IDs, as returned by get_matching_partitions, into
the list index of a subpaths list, as exist in node types such as
Append, MergeAppend and ModifyTable. This allows us to translate a list
of clauses into a Bitmapset of all the subpath indexes which must be
included to satisfy the clause list.
Author: David Rowley, based on an earlier effort by Beena Emerson
Reviewers: Amit Langote, Robert Haas, Amul Sul, Rajkumar Raghuwanshi,
Jesper Pedersen
Discussion: https://postgr.es/m/CAOG9ApE16ac-_VVZVvv0gePSgkg_BwYEV1NBqZFqDR2bBE0X0A@mail.gmail.com
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r-- | src/backend/commands/explain.c | 51 |
1 files changed, 33 insertions, 18 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 79f639d5e27..989b6aad67b 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -118,8 +118,8 @@ static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es); static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es); static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es); -static void ExplainMemberNodes(List *plans, PlanState **planstates, - List *ancestors, ExplainState *es); +static void ExplainMemberNodes(PlanState **planstates, int nsubnodes, + int nplans, List *ancestors, ExplainState *es); static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es); static void ExplainCustomChildren(CustomScanState *css, @@ -1811,28 +1811,33 @@ ExplainNode(PlanState *planstate, List *ancestors, switch (nodeTag(plan)) { case T_ModifyTable: - ExplainMemberNodes(((ModifyTable *) plan)->plans, - ((ModifyTableState *) planstate)->mt_plans, + ExplainMemberNodes(((ModifyTableState *) planstate)->mt_plans, + ((ModifyTableState *) planstate)->mt_nplans, + list_length(((ModifyTable *) plan)->plans), ancestors, es); break; case T_Append: - ExplainMemberNodes(((Append *) plan)->appendplans, - ((AppendState *) planstate)->appendplans, + ExplainMemberNodes(((AppendState *) planstate)->appendplans, + ((AppendState *) planstate)->as_nplans, + list_length(((Append *) plan)->appendplans), ancestors, es); break; case T_MergeAppend: - ExplainMemberNodes(((MergeAppend *) plan)->mergeplans, - ((MergeAppendState *) planstate)->mergeplans, + ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans, + ((MergeAppendState *) planstate)->ms_nplans, + list_length(((MergeAppend *) plan)->mergeplans), ancestors, es); break; case T_BitmapAnd: - ExplainMemberNodes(((BitmapAnd *) plan)->bitmapplans, - ((BitmapAndState *) planstate)->bitmapplans, + ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans, + ((BitmapAndState *) planstate)->nplans, + list_length(((BitmapAnd *) plan)->bitmapplans), ancestors, es); break; case T_BitmapOr: - ExplainMemberNodes(((BitmapOr *) plan)->bitmapplans, - ((BitmapOrState *) planstate)->bitmapplans, + ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans, + ((BitmapOrState *) planstate)->nplans, + list_length(((BitmapOr *) plan)->bitmapplans), ancestors, es); break; case T_SubqueryScan: @@ -3173,18 +3178,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, * * The ancestors list should already contain the immediate parent of these * plans. - * - * Note: we don't actually need to examine the Plan list members, but - * we need the list in order to determine the length of the PlanState array. +* +* nsubnodes indicates the number of items in the planstates array. +* nplans indicates the original number of subnodes in the Plan, some of these +* may have been pruned by the run-time pruning code. */ static void -ExplainMemberNodes(List *plans, PlanState **planstates, +ExplainMemberNodes(PlanState **planstates, int nsubnodes, int nplans, List *ancestors, ExplainState *es) { - int nplans = list_length(plans); int j; - for (j = 0; j < nplans; j++) + /* + * The number of subnodes being lower than the number of subplans that was + * specified in the plan means that some subnodes have been ignored per + * instruction for the partition pruning code during the executor + * initialization. To make this a bit less mysterious, we'll indicate + * here that this has happened. + */ + if (nsubnodes < nplans) + ExplainPropertyInteger("Subplans Removed", NULL, nplans - nsubnodes, es); + + for (j = 0; j < nsubnodes; j++) ExplainNode(planstates[j], ancestors, "Member", NULL, es); } |