mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Suppress creation of backwardly-indexed paths for LATERAL join clauses.
Given a query such as SELECT * FROM foo JOIN LATERAL (SELECT foo.var1) ss(x) ON ss.x = foo.var2 the existence of the join clause "ss.x = foo.var2" encourages indxpath.c to build a parameterized path for foo using any index available for foo.var2. This is completely useless activity, though, since foo has got to be on the outside not the inside of any nestloop join with ss. It's reasonably inexpensive to add tests that prevent creation of such paths, so let's do that.
This commit is contained in:
parent
35738b5906
commit
77387f0ac8
@ -1969,11 +1969,15 @@ mutate_eclass_expressions(PlannerInfo *root,
|
|||||||
* is no value in using more than one. (But it *is* worthwhile to create
|
* is no value in using more than one. (But it *is* worthwhile to create
|
||||||
* a separate parameterized path for each one, since that leads to different
|
* a separate parameterized path for each one, since that leads to different
|
||||||
* join orders.)
|
* join orders.)
|
||||||
|
*
|
||||||
|
* The caller can pass a Relids set of rels we aren't interested in joining
|
||||||
|
* to, so as to save the work of creating useless clauses.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
generate_implied_equalities_for_indexcol(PlannerInfo *root,
|
generate_implied_equalities_for_indexcol(PlannerInfo *root,
|
||||||
IndexOptInfo *index,
|
IndexOptInfo *index,
|
||||||
int indexcol)
|
int indexcol,
|
||||||
|
Relids prohibited_rels)
|
||||||
{
|
{
|
||||||
List *result = NIL;
|
List *result = NIL;
|
||||||
RelOptInfo *rel = index->rel;
|
RelOptInfo *rel = index->rel;
|
||||||
@ -2050,6 +2054,10 @@ generate_implied_equalities_for_indexcol(PlannerInfo *root,
|
|||||||
bms_overlap(other_em->em_relids, rel->relids))
|
bms_overlap(other_em->em_relids, rel->relids))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Forget it if caller doesn't want joins to this rel */
|
||||||
|
if (bms_overlap(other_em->em_relids, prohibited_rels))
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also, if this is a child rel, avoid generating a useless join
|
* Also, if this is a child rel, avoid generating a useless join
|
||||||
* to its parent rel.
|
* to its parent rel.
|
||||||
|
@ -121,10 +121,12 @@ static void match_restriction_clauses_to_index(RelOptInfo *rel,
|
|||||||
IndexClauseSet *clauseset);
|
IndexClauseSet *clauseset);
|
||||||
static void match_join_clauses_to_index(PlannerInfo *root,
|
static void match_join_clauses_to_index(PlannerInfo *root,
|
||||||
RelOptInfo *rel, IndexOptInfo *index,
|
RelOptInfo *rel, IndexOptInfo *index,
|
||||||
|
Relids lateral_referencers,
|
||||||
IndexClauseSet *clauseset,
|
IndexClauseSet *clauseset,
|
||||||
List **joinorclauses);
|
List **joinorclauses);
|
||||||
static void match_eclass_clauses_to_index(PlannerInfo *root,
|
static void match_eclass_clauses_to_index(PlannerInfo *root,
|
||||||
IndexOptInfo *index,
|
IndexOptInfo *index,
|
||||||
|
Relids lateral_referencers,
|
||||||
IndexClauseSet *clauseset);
|
IndexClauseSet *clauseset);
|
||||||
static void match_clauses_to_index(IndexOptInfo *index,
|
static void match_clauses_to_index(IndexOptInfo *index,
|
||||||
List *clauses,
|
List *clauses,
|
||||||
@ -211,22 +213,40 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
List *bitindexpaths;
|
List *bitindexpaths;
|
||||||
List *bitjoinpaths;
|
List *bitjoinpaths;
|
||||||
List *joinorclauses;
|
List *joinorclauses;
|
||||||
|
Relids lateral_referencers;
|
||||||
IndexClauseSet rclauseset;
|
IndexClauseSet rclauseset;
|
||||||
IndexClauseSet jclauseset;
|
IndexClauseSet jclauseset;
|
||||||
IndexClauseSet eclauseset;
|
IndexClauseSet eclauseset;
|
||||||
ListCell *ilist;
|
ListCell *lc;
|
||||||
|
|
||||||
/* Skip the whole mess if no indexes */
|
/* Skip the whole mess if no indexes */
|
||||||
if (rel->indexlist == NIL)
|
if (rel->indexlist == NIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are any rels that have LATERAL references to this one, we
|
||||||
|
* cannot use join quals referencing them as index quals for this one,
|
||||||
|
* since such rels would have to be on the inside not the outside of a
|
||||||
|
* nestloop join relative to this one. Create a Relids set listing all
|
||||||
|
* such rels, for use in checks of potential join clauses.
|
||||||
|
*/
|
||||||
|
lateral_referencers = NULL;
|
||||||
|
foreach(lc, root->lateral_info_list)
|
||||||
|
{
|
||||||
|
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc);
|
||||||
|
|
||||||
|
if (bms_is_member(rel->relid, ljinfo->lateral_lhs))
|
||||||
|
lateral_referencers = bms_add_member(lateral_referencers,
|
||||||
|
ljinfo->lateral_rhs);
|
||||||
|
}
|
||||||
|
|
||||||
/* Bitmap paths are collected and then dealt with at the end */
|
/* Bitmap paths are collected and then dealt with at the end */
|
||||||
bitindexpaths = bitjoinpaths = joinorclauses = NIL;
|
bitindexpaths = bitjoinpaths = joinorclauses = NIL;
|
||||||
|
|
||||||
/* Examine each index in turn */
|
/* Examine each index in turn */
|
||||||
foreach(ilist, rel->indexlist)
|
foreach(lc, rel->indexlist)
|
||||||
{
|
{
|
||||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
|
IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
|
||||||
|
|
||||||
/* Protect limited-size array in IndexClauseSets */
|
/* Protect limited-size array in IndexClauseSets */
|
||||||
Assert(index->ncolumns <= INDEX_MAX_KEYS);
|
Assert(index->ncolumns <= INDEX_MAX_KEYS);
|
||||||
@ -260,7 +280,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
* EquivalenceClasses. Also, collect join OR clauses for later.
|
* EquivalenceClasses. Also, collect join OR clauses for later.
|
||||||
*/
|
*/
|
||||||
MemSet(&jclauseset, 0, sizeof(jclauseset));
|
MemSet(&jclauseset, 0, sizeof(jclauseset));
|
||||||
match_join_clauses_to_index(root, rel, index,
|
match_join_clauses_to_index(root, rel, index, lateral_referencers,
|
||||||
&jclauseset, &joinorclauses);
|
&jclauseset, &joinorclauses);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -268,7 +288,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
* the index.
|
* the index.
|
||||||
*/
|
*/
|
||||||
MemSet(&eclauseset, 0, sizeof(eclauseset));
|
MemSet(&eclauseset, 0, sizeof(eclauseset));
|
||||||
match_eclass_clauses_to_index(root, index, &eclauseset);
|
match_eclass_clauses_to_index(root, index, lateral_referencers,
|
||||||
|
&eclauseset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we found any plain or eclass join clauses, decide what to do
|
* If we found any plain or eclass join clauses, decide what to do
|
||||||
@ -1796,6 +1817,7 @@ match_restriction_clauses_to_index(RelOptInfo *rel, IndexOptInfo *index,
|
|||||||
static void
|
static void
|
||||||
match_join_clauses_to_index(PlannerInfo *root,
|
match_join_clauses_to_index(PlannerInfo *root,
|
||||||
RelOptInfo *rel, IndexOptInfo *index,
|
RelOptInfo *rel, IndexOptInfo *index,
|
||||||
|
Relids lateral_referencers,
|
||||||
IndexClauseSet *clauseset,
|
IndexClauseSet *clauseset,
|
||||||
List **joinorclauses)
|
List **joinorclauses)
|
||||||
{
|
{
|
||||||
@ -1810,6 +1832,10 @@ match_join_clauses_to_index(PlannerInfo *root,
|
|||||||
if (!join_clause_is_movable_to(rinfo, rel->relid))
|
if (!join_clause_is_movable_to(rinfo, rel->relid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Not useful if it conflicts with any LATERAL references */
|
||||||
|
if (bms_overlap(rinfo->clause_relids, lateral_referencers))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Potentially usable, so see if it matches the index or is an OR */
|
/* Potentially usable, so see if it matches the index or is an OR */
|
||||||
if (restriction_is_or_clause(rinfo))
|
if (restriction_is_or_clause(rinfo))
|
||||||
*joinorclauses = lappend(*joinorclauses, rinfo);
|
*joinorclauses = lappend(*joinorclauses, rinfo);
|
||||||
@ -1825,6 +1851,7 @@ match_join_clauses_to_index(PlannerInfo *root,
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index,
|
match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index,
|
||||||
|
Relids lateral_referencers,
|
||||||
IndexClauseSet *clauseset)
|
IndexClauseSet *clauseset)
|
||||||
{
|
{
|
||||||
int indexcol;
|
int indexcol;
|
||||||
@ -1837,9 +1864,11 @@ match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index,
|
|||||||
{
|
{
|
||||||
List *clauses;
|
List *clauses;
|
||||||
|
|
||||||
|
/* Generate clauses, skipping any that join to lateral_referencers */
|
||||||
clauses = generate_implied_equalities_for_indexcol(root,
|
clauses = generate_implied_equalities_for_indexcol(root,
|
||||||
index,
|
index,
|
||||||
indexcol);
|
indexcol,
|
||||||
|
lateral_referencers);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to check whether the results actually do match the index,
|
* We have to check whether the results actually do match the index,
|
||||||
|
@ -127,7 +127,8 @@ extern void mutate_eclass_expressions(PlannerInfo *root,
|
|||||||
void *context);
|
void *context);
|
||||||
extern List *generate_implied_equalities_for_indexcol(PlannerInfo *root,
|
extern List *generate_implied_equalities_for_indexcol(PlannerInfo *root,
|
||||||
IndexOptInfo *index,
|
IndexOptInfo *index,
|
||||||
int indexcol);
|
int indexcol,
|
||||||
|
Relids prohibited_rels);
|
||||||
extern bool have_relevant_eclass_joinclause(PlannerInfo *root,
|
extern bool have_relevant_eclass_joinclause(PlannerInfo *root,
|
||||||
RelOptInfo *rel1, RelOptInfo *rel2);
|
RelOptInfo *rel1, RelOptInfo *rel2);
|
||||||
extern bool has_relevant_eclass_joinclause(PlannerInfo *root,
|
extern bool has_relevant_eclass_joinclause(PlannerInfo *root,
|
||||||
|
Loading…
Reference in New Issue
Block a user