diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b22b36ec0e..dbe0c1cb14 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -2029,6 +2029,8 @@ exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2) */ EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, + EquivalenceClass **eclasses, + Bitmapset **eclass_index, ForeignKeyOptInfo *fkinfo, int colno) { @@ -2038,23 +2040,29 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root, AttrNumber var2attno = fkinfo->confkey[colno]; Oid eqop = fkinfo->conpfeqop[colno]; List *opfamilies = NIL; /* compute only if needed */ - ListCell *lc1; + Bitmapset *matching_ecs; + int i; - foreach(lc1, root->eq_classes) + /* Determine which eclasses contain members for both of the relations */ + matching_ecs = bms_intersect(eclass_index[var1varno], + eclass_index[var2varno]); + + i = -1; + while ((i = bms_next_member(matching_ecs, i)) >= 0) { - EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1); + EquivalenceClass *ec = eclasses[i]; bool item1member = false; bool item2member = false; - ListCell *lc2; + ListCell *lc; /* Never match to a volatile EC */ if (ec->ec_has_volatile) continue; /* Note: it seems okay to match to "broken" eclasses here */ - foreach(lc2, ec->ec_members) + foreach(lc, ec->ec_members) { - EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2); + EquivalenceMember *em = (EquivalenceMember *) lfirst(lc); Var *var; if (em->em_is_child) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 01335db511..f826a4612a 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -2440,6 +2440,41 @@ match_foreign_keys_to_quals(PlannerInfo *root) { List *newlist = NIL; ListCell *lc; + EquivalenceClass **eclasses; + Bitmapset **eclass_index; + int i; + + eclasses = palloc(sizeof(EquivalenceClass *) * + list_length(root->eq_classes)); + eclass_index = palloc0(sizeof(Bitmapset *) * root->simple_rel_array_size); + + /* + * Index the eclass list so that we can quickly identify eclasses + * belonging to a given relation. First we build an array to store + * each eclasss, this allows us to quickly lookup the eclass by array + * index. We then build an index using a Bitmapset for each relation to + * mark which eclass array element contains a member for that relation. + */ + i = 0; + foreach(lc, root->eq_classes) + eclasses[i++] = lfirst(lc); + + /* + * We could build the indexes in the loop above, but looping backwards + * allows the Bitmapset to be allocated to its final size on the first + * allocation. Doing this forward could cause small incremental + * allocations which can be slower. + */ + for (i--; i >= 0; i--) + { + int j = -1; + + while ((j = bms_next_member(eclasses[i]->ec_relids, j)) > 0) + { + Assert(j < root->simple_rel_array_size); + eclass_index[j] = bms_add_member(eclass_index[j], i); + } + } foreach(lc, root->fkey_list) { @@ -2489,6 +2524,8 @@ match_foreign_keys_to_quals(PlannerInfo *root) ListCell *lc2; fkinfo->eclass[colno] = match_eclasses_to_foreign_key_col(root, + eclasses, + eclass_index, fkinfo, colno); /* Don't bother looking for loose quals if we got an EC match */ @@ -2586,6 +2623,9 @@ match_foreign_keys_to_quals(PlannerInfo *root) } /* Replace fkey_list, thereby discarding any useless entries */ root->fkey_list = newlist; + + pfree(eclasses); + pfree(eclass_index); } diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index cafde307ad..123946b50f 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -156,6 +156,8 @@ extern List *generate_join_implied_equalities_for_ecs(PlannerInfo *root, RelOptInfo *inner_rel); extern bool exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2); extern EquivalenceClass *match_eclasses_to_foreign_key_col(PlannerInfo *root, + EquivalenceClass **eclasses, + Bitmapset **eclass_index, ForeignKeyOptInfo *fkinfo, int colno); extern void add_child_rel_equivalences(PlannerInfo *root,