1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-25 21:42:33 +03:00

Fix missed optimization in relation_excluded_by_constraints().

In commit 3fc6e2d7f, I (tgl) argued that we only need to check for
a constant-FALSE restriction clause when there's exactly one
restriction clause, on the grounds that const-folding would have
thrown away anything ANDed with a Const FALSE.  That's true just after
const-folding has been applied, but subsequent processing such as
equivalence class expansion could result in cases where a Const FALSE
is ANDed with some other stuff.  (Compare for instance joinrels.c's
restriction_is_constant_false.)  Hence, tweak this logic to check all
the elements of the baserestrictinfo list, not just one; that's cheap
enough to not be worth worrying about.

There is one existing test case where this visibly improves the plan.
There would not be any savings in runtime, but the planner effort and
executor startup effort will be reduced, and anyway it's odd that
we can detect related cases but not this one.

Richard Guo (independently discovered by David Rowley)

Discussion: https://postgr.es/m/CAMbWs4_x3-CnVVrCboS1LkEhB5V+W7sLSCabsRiG+n7+5_kqbg@mail.gmail.com
This commit is contained in:
Tom Lane 2023-10-11 12:51:38 -04:00
parent 16671ba6e7
commit 5d8aa8bced
2 changed files with 12 additions and 13 deletions

View File

@ -1549,16 +1549,17 @@ relation_excluded_by_constraints(PlannerInfo *root,
/* /*
* Regardless of the setting of constraint_exclusion, detect * Regardless of the setting of constraint_exclusion, detect
* constant-FALSE-or-NULL restriction clauses. Because const-folding will * constant-FALSE-or-NULL restriction clauses. Although const-folding
* reduce "anything AND FALSE" to just "FALSE", any such case should * will reduce "anything AND FALSE" to just "FALSE", the baserestrictinfo
* result in exactly one baserestrictinfo entry. This doesn't fire very * list can still have other members besides the FALSE constant, due to
* often, but it seems cheap enough to be worth doing anyway. (Without * qual pushdown and other mechanisms; so check them all. This doesn't
* this, we'd miss some optimizations that 9.5 and earlier found via much * fire very often, but it seems cheap enough to be worth doing anyway.
* more roundabout methods.) * (Without this, we'd miss some optimizations that 9.5 and earlier found
* via much more roundabout methods.)
*/ */
if (list_length(rel->baserestrictinfo) == 1) foreach(lc, rel->baserestrictinfo)
{ {
RestrictInfo *rinfo = (RestrictInfo *) linitial(rel->baserestrictinfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
Expr *clause = rinfo->clause; Expr *clause = rinfo->clause;
if (clause && IsA(clause, Const) && if (clause && IsA(clause, Const) &&

View File

@ -5788,13 +5788,11 @@ explain (costs off)
select p.* from select p.* from
parent p left join child c on (p.k = c.k) parent p left join child c on (p.k = c.k)
where p.k = 1 and p.k = 2; where p.k = 1 and p.k = 2;
QUERY PLAN QUERY PLAN
------------------------------------------------ --------------------------
Result Result
One-Time Filter: false One-Time Filter: false
-> Index Scan using parent_pkey on parent p (2 rows)
Index Cond: (k = 1)
(4 rows)
select p.* from select p.* from
(parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k