1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Don't constraint-exclude partitioned tables as much

We only need to invoke constraint exclusion on partitioned tables when
they are a partition, and they themselves contain a default partition;
it's not necessary otherwise, and it's expensive, so avoid it.  Also, we
were trying once for each clause separately, but we can do it for all
the clauses at once.

While at it, centralize setting of RelOptInfo->partition_qual instead of
computing it in slightly different ways in different places.

Per complaints from Simon Riggs about 4e85642d935e; reviewed by Yuzuko
Hosoya, Kyotaro Horiguchi.

Author: Amit Langote.  I (Álvaro) again mangled the patch somewhat.
Discussion: https://postgr.es/m/CANP8+j+tMCY=nEcQeqQam85=uopLBtX-2vHiLD2bbp7iQQUKpA@mail.gmail.com
This commit is contained in:
Alvaro Herrera
2019-08-13 10:26:04 -04:00
parent 416c75cf38
commit 815ef2f568
2 changed files with 65 additions and 65 deletions

View File

@ -619,31 +619,16 @@ gen_partprune_steps(RelOptInfo *rel, List *clauses, PartClauseTarget target,
context->target = target;
/*
* For sub-partitioned tables there's a corner case where if the
* sub-partitioned table shares any partition keys with its parent, then
* it's possible that the partitioning hierarchy allows the parent
* partition to only contain a narrower range of values than the
* sub-partitioned table does. In this case it is possible that we'd
* include partitions that could not possibly have any tuples matching
* 'clauses'. The possibility of such a partition arrangement is perhaps
* unlikely for non-default partitions, but it may be more likely in the
* case of default partitions, so we'll add the parent partition table's
* partition qual to the clause list in this case only. This may result
* in the default partition being eliminated.
* If this partitioned table is in turn a partition, and it shares any
* partition keys with its parent, then it's possible that the hierarchy
* allows the parent a narrower range of values than some of its
* partitions (particularly the default one). This is normally not
* useful, but it can be to prune the default partition.
*/
if (partition_bound_has_default(rel->boundinfo) &&
rel->partition_qual != NIL)
if (partition_bound_has_default(rel->boundinfo) && rel->partition_qual)
{
List *partqual = rel->partition_qual;
partqual = (List *) expression_planner((Expr *) partqual);
/* Fix Vars to have the desired varno */
if (rel->relid != 1)
ChangeVarNodes((Node *) partqual, 1, rel->relid, 0);
/* Make a copy to avoid modifying the passed-in List */
clauses = list_concat_copy(clauses, partqual);
clauses = list_concat_copy(clauses, rel->partition_qual);
}
/* Down into the rabbit-hole. */
@ -867,6 +852,25 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
List *result = NIL;
ListCell *lc;
/*
* If this partitioned relation has a default partition and is itself
* a partition (as evidenced by partition_qual being not NIL), we first
* check if the clauses contradict the partition constraint. If they do,
* there's no need to generate any steps as it'd already be proven that no
* partitions need to be scanned.
*
* This is a measure of last resort only to be used because the default
* partition cannot be pruned using the steps generated from clauses that
* contradict the parent's partition constraint; regular pruning, which is
* cheaper, is sufficient when no default partition exists.
*/
if (partition_bound_has_default(context->rel->boundinfo) &&
predicate_refuted_by(context->rel->partition_qual, clauses, false))
{
context->contradictory = true;
return NIL;
}
memset(keyclauses, 0, sizeof(keyclauses));
foreach(lc, clauses)
{
@ -1019,29 +1023,6 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
*/
}
/*
* If the clause contradicts the partition constraint, mark the clause
* as contradictory and we're done. This is particularly helpful to
* prune the default partition.
*/
if (context->rel->partition_qual)
{
List *partconstr;
partconstr = (List *)
expression_planner((Expr *) context->rel->partition_qual);
if (context->rel->relid != 1)
ChangeVarNodes((Node *) partconstr, 1,
context->rel->relid, 0);
if (predicate_refuted_by(partconstr,
list_make1(clause),
false))
{
context->contradictory = true;
return NIL;
}
}
/*
* See if we can match this clause to any of the partition keys.
*/