Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1746ba9

Browse files
committed
Improve check_partial_indexes() to consider join clauses in proof attempts.
Traditionally check_partial_indexes() has only looked at restriction clauses while trying to prove partial indexes usable in queries. However, join clauses can also be used in some cases; mainly, that a strict operator on "x" proves an "x IS NOT NULL" index predicate, even if the operator is in a join clause rather than a restriction clause. Adding this code fixes a regression in 9.2, because previously we would take join clauses into account when considering whether a partial index could be used in a nestloop inner indexscan path. 9.2 doesn't handle nestloop inner indexscans in the same way, and this consideration was overlooked in the rewrite. Moving the work to check_partial_indexes() is a better solution anyway, since the proof applies whether or not we actually use the index in that particular way, and we don't have to do it over again for each possible outer relation. Per report from Dave Cramer.
1 parent 817c186 commit 1746ba9

File tree

1 file changed

+76
-6
lines changed

1 file changed

+76
-6
lines changed

src/backend/optimizer/path/indxpath.c

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,21 +2589,91 @@ match_clause_to_ordering_op(IndexOptInfo *index,
25892589
void
25902590
check_partial_indexes(PlannerInfo *root, RelOptInfo *rel)
25912591
{
2592-
List *restrictinfo_list = rel->baserestrictinfo;
2593-
ListCell *ilist;
2592+
List *clauselist;
2593+
bool have_partial;
2594+
Relids otherrels;
2595+
ListCell *lc;
25942596

2595-
foreach(ilist, rel->indexlist)
2597+
/*
2598+
* Frequently, there will be no partial indexes, so first check to make
2599+
* sure there's something useful to do here.
2600+
*/
2601+
have_partial = false;
2602+
foreach(lc, rel->indexlist)
25962603
{
2597-
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
2604+
IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
2605+
2606+
if (index->indpred == NIL)
2607+
continue; /* ignore non-partial indexes */
2608+
2609+
if (index->predOK)
2610+
continue; /* don't repeat work if already proven OK */
2611+
2612+
have_partial = true;
2613+
break;
2614+
}
2615+
if (!have_partial)
2616+
return;
2617+
2618+
/*
2619+
* Construct a list of clauses that we can assume true for the purpose
2620+
* of proving the index(es) usable. Restriction clauses for the rel are
2621+
* always usable, and so are any join clauses that are "movable to" this
2622+
* rel. Also, we can consider any EC-derivable join clauses (which must
2623+
* be "movable to" this rel, by definition).
2624+
*/
2625+
clauselist = list_copy(rel->baserestrictinfo);
2626+
2627+
/* Scan the rel's join clauses */
2628+
foreach(lc, rel->joininfo)
2629+
{
2630+
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2631+
2632+
/* Check if clause can be moved to this rel */
2633+
if (!join_clause_is_movable_to(rinfo, rel->relid))
2634+
continue;
2635+
2636+
clauselist = lappend(clauselist, rinfo);
2637+
}
2638+
2639+
/*
2640+
* Add on any equivalence-derivable join clauses. Computing the correct
2641+
* relid sets for generate_join_implied_equalities is slightly tricky
2642+
* because the rel could be a child rel rather than a true baserel, and
2643+
* in that case we must remove its parent's relid from all_baserels.
2644+
*/
2645+
if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
2646+
{
2647+
/* Lookup parent->child translation data */
2648+
AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
2649+
2650+
otherrels = bms_difference(root->all_baserels,
2651+
bms_make_singleton(appinfo->parent_relid));
2652+
}
2653+
else
2654+
otherrels = bms_difference(root->all_baserels, rel->relids);
2655+
2656+
if (!bms_is_empty(otherrels))
2657+
clauselist =
2658+
list_concat(clauselist,
2659+
generate_join_implied_equalities(root,
2660+
bms_union(rel->relids,
2661+
otherrels),
2662+
otherrels,
2663+
rel));
2664+
2665+
/* Now try to prove each index predicate true */
2666+
foreach(lc, rel->indexlist)
2667+
{
2668+
IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
25982669

25992670
if (index->indpred == NIL)
26002671
continue; /* ignore non-partial indexes */
26012672

26022673
if (index->predOK)
26032674
continue; /* don't repeat work if already proven OK */
26042675

2605-
index->predOK = predicate_implied_by(index->indpred,
2606-
restrictinfo_list);
2676+
index->predOK = predicate_implied_by(index->indpred, clauselist);
26072677
}
26082678
}
26092679

0 commit comments

Comments
 (0)