0003-Implement-optimizations-based-on-Bitmapset.patch
application/octet-stream
Filename: 0003-Implement-optimizations-based-on-Bitmapset.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0003
Subject: Implement optimizations based on Bitmapset
| File | + | − |
|---|---|---|
| contrib/postgres_fdw/postgres_fdw.c | 10 | 7 |
| src/backend/optimizer/path/allpaths.c | 1 | 1 |
| src/backend/optimizer/path/equivclass.c | 122 | 78 |
| src/backend/optimizer/path/indxpath.c | 6 | 4 |
| src/backend/optimizer/path/pathkeys.c | 16 | 11 |
| src/backend/optimizer/plan/planner.c | 2 | 0 |
| src/backend/optimizer/prep/prepjointree.c | 2 | 0 |
| src/backend/optimizer/util/relnode.c | 8 | 0 |
| src/include/nodes/pathnodes.h | 12 | 0 |
| src/include/optimizer/paths.h | 150 | 2 |
From eb6e080b3053c4b45d97989f420e08e310b362c1 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Mon, 8 Aug 2022 15:51:36 +0900
Subject: [PATCH 3/3] Implement optimizations based on Bitmapset
---
contrib/postgres_fdw/postgres_fdw.c | 17 +-
src/backend/optimizer/path/allpaths.c | 2 +-
src/backend/optimizer/path/equivclass.c | 200 +++++++++++++---------
src/backend/optimizer/path/indxpath.c | 10 +-
src/backend/optimizer/path/pathkeys.c | 27 +--
src/backend/optimizer/plan/planner.c | 2 +
src/backend/optimizer/prep/prepjointree.c | 2 +
src/backend/optimizer/util/relnode.c | 8 +
src/include/nodes/pathnodes.h | 12 ++
src/include/optimizer/paths.h | 152 +++++++++++++++-
10 files changed, 329 insertions(+), 103 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6bbf10d679..d2b69a4171 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -7413,17 +7413,19 @@ EquivalenceMember *
find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
{
int i = -1;
+ Bitmapset *matching_ems =
+ get_eclass_members_indexes_for_subsets_of_relids(root, ec, rel->relids);
- while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+ Assert(bms_is_subset(em->em_relids, rel->relids));
/*
* Note we require !bms_is_empty, else we'd accept constant
* expressions which are not suitable for the purpose.
*/
- if (bms_is_subset(em->em_relids, rel->relids) &&
- !bms_is_empty(em->em_relids) &&
+ if (!bms_is_empty(em->em_relids) &&
is_foreign_expr(root, rel, em->em_expr))
return em;
}
@@ -7456,6 +7458,7 @@ find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
Expr *expr = (Expr *) lfirst(lc1);
Index sgref = get_pathtarget_sortgroupref(target, i);
int j;
+ Bitmapset *matching_ems;
/* Ignore non-sort expressions */
if (sgref == 0 ||
@@ -7472,7 +7475,9 @@ find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
/* Locate an EquivalenceClass member matching this expr, if any */
j = -1;
- while ((j = bms_next_member(ec->ec_member_indexes, j)) >= 0)
+ /* Ignore child members */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, ec);
+ while ((j = bms_next_member(matching_ems, j)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
Expr *em_expr;
@@ -7481,9 +7486,7 @@ find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
if (em->em_is_const)
continue;
- /* Ignore child members */
- if (em->em_is_child)
- continue;
+ Assert(!em->em_is_child);
/* Match if same expression (after stripping relabel) */
em_expr = em->em_expr;
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 9b6a5b08dc..394ae1483f 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -2755,7 +2755,7 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
(Expr *) var,
NULL, /* below outer joins */
Int8LessOperator,
- rel->relids,
+ rel,
false);
}
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 90c96de7d8..44505c0c36 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -378,19 +378,30 @@ process_equivalence(PlannerInfo *root,
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
int em_index = list_length(root->eq_members);
int j;
+ bool relids_is_empty;
ec1->ec_member_indexes = bms_add_member(ec1->ec_member_indexes, em_index);
root->eq_members = lappend(root->eq_members, em);
j = -1;
+ relids_is_empty = true;
while ((j = bms_next_member(em->em_relids, j)) > 0)
{
RelOptInfo *rel = root->simple_rel_array[j];
+
+ relids_is_empty = false;
+ rel->eclass_referencing_member_indexes =
+ bms_add_member(rel->eclass_referencing_member_indexes, em_index);
if (bms_equal(rel->relids, em->em_relids))
{
rel->eclass_member_indexes = bms_add_member(rel->eclass_member_indexes, em_index);
}
}
+
+ if (relids_is_empty)
+ {
+ root->eq_empty_relids_indexes = bms_add_member(root->eq_empty_relids_indexes, em_index);
+ }
}
ec1->ec_sources = list_concat(ec1->ec_sources, ec2->ec_sources);
ec1->ec_derives = list_concat(ec1->ec_derives, ec2->ec_derives);
@@ -576,6 +587,7 @@ add_eq_member(PlannerInfo *root, EquivalenceClass *ec, Expr *expr,
EquivalenceMember *em = makeNode(EquivalenceMember);
int em_index;
int i;
+ bool relids_is_empty;
em->em_expr = expr;
em->em_relids = relids;
@@ -606,17 +618,32 @@ add_eq_member(PlannerInfo *root, EquivalenceClass *ec, Expr *expr,
em_index = list_length(root->eq_members);
ec->ec_member_indexes = bms_add_member(ec->ec_member_indexes, em_index);
root->eq_members = lappend(root->eq_members, em);
+ if (!is_child)
+ {
+ root->eq_not_children_indexes = bms_add_member(root->eq_not_children_indexes,
+ em_index);
+ }
i = -1;
+ relids_is_empty = true;
while ((i = bms_next_member(relids, i)) > 0)
{
RelOptInfo *rel = root->simple_rel_array[i];
+
+ relids_is_empty = false;
+ rel->eclass_referencing_member_indexes =
+ bms_add_member(rel->eclass_referencing_member_indexes, em_index);
if (bms_equal(rel->relids, relids))
{
rel->eclass_member_indexes = bms_add_member(rel->eclass_member_indexes, em_index);
}
}
+ if (relids_is_empty)
+ {
+ root->eq_empty_relids_indexes = bms_add_member(root->eq_empty_relids_indexes, em_index);
+ }
+
return em;
}
@@ -667,7 +694,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
Oid opcintype,
Oid collation,
Index sortref,
- Relids rel,
+ RelOptInfo *rel,
bool create_it)
{
Relids expr_relids;
@@ -688,6 +715,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
{
EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
int i;
+ Bitmapset *matching_ems;
/*
* Never match to a volatile EC, except when we are looking at another
@@ -702,17 +730,16 @@ get_eclass_for_sort_expr(PlannerInfo *root,
if (!equal(opfamilies, cur_ec->ec_opfamilies))
continue;
+ /*
+ * Ignore child members unless they match the request.
+ */
+ matching_ems =
+ get_eclass_members_indexes_for_relids_or_not_children(root, cur_ec, rel);
i = -1;
- while ((i = bms_next_member(cur_ec->ec_member_indexes, i)) >= 0)
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *cur_em = (EquivalenceMember *) list_nth(root->eq_members, i);
-
- /*
- * Ignore child members unless they match the request.
- */
- if (cur_em->em_is_child &&
- !bms_equal(cur_em->em_relids, rel))
- continue;
+ Assert(!cur_em->em_is_child || bms_equal(cur_em->em_relids, rel->relids));
/*
* If below an outer join, don't match constants: they're not as
@@ -809,13 +836,13 @@ get_eclass_for_sort_expr(PlannerInfo *root,
while ((i = bms_next_member(newec->ec_relids, i)) > 0)
{
- RelOptInfo *rel = root->simple_rel_array[i];
+ RelOptInfo *rel2 = root->simple_rel_array[i];
- Assert(rel->reloptkind == RELOPT_BASEREL ||
- rel->reloptkind == RELOPT_DEADREL);
+ Assert(rel2->reloptkind == RELOPT_BASEREL ||
+ rel2->reloptkind == RELOPT_DEADREL);
- rel->eclass_indexes = bms_add_member(rel->eclass_indexes,
- ec_index);
+ rel2->eclass_indexes = bms_add_member(rel2->eclass_indexes,
+ ec_index);
}
}
@@ -843,13 +870,19 @@ find_ec_member_matching_expr(PlannerInfo *root,
Relids relids)
{
int i;
+ Bitmapset *matching_ems;
/* We ignore binary-compatible relabeling on both ends */
while (expr && IsA(expr, RelabelType))
expr = ((RelabelType *) expr)->arg;
+ /*
+ * Ignore child members unless they belong to the requested rel.
+ */
+ matching_ems =
+ get_eclass_members_indexes_for_subsets_of_relids_or_not_children(root, ec, relids);
i = -1;
- while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
Expr *emexpr;
@@ -861,12 +894,7 @@ find_ec_member_matching_expr(PlannerInfo *root,
if (em->em_is_const)
continue;
- /*
- * Ignore child members unless they belong to the requested rel.
- */
- if (em->em_is_child &&
- !bms_is_subset(em->em_relids, relids))
- continue;
+ Assert(!em->em_is_child || bms_is_subset(em->em_relids, relids));
/*
* Match if same expression (after stripping relabel).
@@ -912,7 +940,13 @@ find_computable_ec_member(PlannerInfo *root,
{
int i = -1;
- while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+ /*
+ * Ignore child members unless they belong to the requested rel.
+ */
+ Bitmapset *matching_ems =
+ get_eclass_members_indexes_for_subsets_of_relids_or_not_children(root, ec, relids);
+
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
List *exprvars;
@@ -925,12 +959,7 @@ find_computable_ec_member(PlannerInfo *root,
if (em->em_is_const)
continue;
- /*
- * Ignore child members unless they belong to the requested rel.
- */
- if (em->em_is_child &&
- !bms_is_subset(em->em_relids, relids))
- continue;
+ Assert(!em->em_is_child || bms_is_subset(em->em_relids, relids));
/*
* Match if all Vars and quasi-Vars are available in "exprs".
@@ -1610,6 +1639,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
List *inner_members = NIL;
ListCell *lc1;
int i;
+ Bitmapset *matching_ems;
/*
* First, scan the EC to identify member values that are computable at the
@@ -1620,18 +1650,17 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
* as well as to at least one input member, plus enforce at least one
* outer-rel member equal to at least one inner-rel member.
*/
+ /*
+ * We don't need to check explicitly for child EC members. This test
+ * against join_relids will cause them to be ignored except when
+ * considering a child inner rel, which is what we want.
+ */
+ matching_ems = get_eclass_members_indexes_for_subsets_of_relids(root, ec, join_relids);
i = -1;
- while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *cur_em = (EquivalenceMember *)list_nth(root->eq_members, i);
-
- /*
- * We don't need to check explicitly for child EC members. This test
- * against join_relids will cause them to be ignored except when
- * considering a child inner rel, which is what we want.
- */
- if (!bms_is_subset(cur_em->em_relids, join_relids))
- continue; /* not computable yet, or wrong child */
+ Assert(bms_is_subset(cur_em->em_relids, join_relids));
if (bms_is_subset(cur_em->em_relids, outer_relids))
outer_members = lappend(outer_members, cur_em);
@@ -2392,12 +2421,16 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
if (matchleft && matchright)
{
cur_ec->ec_member_indexes = bms_del_member(cur_ec->ec_member_indexes, coal_idx);
+ root->eq_not_children_indexes = bms_del_member(root->eq_not_children_indexes,
+ coal_idx);
/* Remove the member from each of the relations */
i = -1;
while ((i = bms_next_member(coal_em->em_relids, i)) > 0)
{
RelOptInfo *rel = root->simple_rel_array[i];
+ rel->eclass_referencing_member_indexes =
+ bms_del_member(rel->eclass_referencing_member_indexes, coal_idx);
if (bms_equal(rel->relids, coal_em->em_relids))
{
rel->eclass_member_indexes = bms_del_member(rel->eclass_member_indexes, coal_idx);
@@ -2442,18 +2475,20 @@ exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2)
bool item1member = false;
bool item2member = false;
int i;
+ Bitmapset *matching_ems;
/* Never match to a volatile EC */
if (ec->ec_has_volatile)
continue;
i = -1;
- while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, ec);
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+ Assert(!em->em_is_child);
- if (em->em_is_child)
- continue; /* ignore children here */
if (equal(item1, em->em_expr))
item1member = true;
else if (equal(item2, em->em_expr))
@@ -2514,6 +2549,7 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
EquivalenceMember *item1_em = NULL;
EquivalenceMember *item2_em = NULL;
int j;
+ Bitmapset *matching_ems;
/* Never match to a volatile EC */
if (ec->ec_has_volatile)
@@ -2521,13 +2557,14 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
/* Note: it seems okay to match to "broken" eclasses here */
j = -1;
- while ((j = bms_next_member(ec->ec_member_indexes, j)) >= 0)
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, ec);
+ while ((j = bms_next_member(matching_ems, j)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
Var *var;
- if (em->em_is_child)
- continue; /* ignore children here */
+ Assert(!em->em_is_child);
/* EM must be a Var, possibly with RelabelType */
var = (Var *) em->em_expr;
@@ -2636,8 +2673,9 @@ add_child_rel_equivalences(PlannerInfo *root,
while ((i = bms_next_member(parent_rel->eclass_indexes, i)) >= 0)
{
EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
- int num_members;
+ int final_member;
int j;
+ Bitmapset *matching_ems;
/*
* If this EC contains a volatile expression, then generating child
@@ -2656,28 +2694,28 @@ add_child_rel_equivalences(PlannerInfo *root,
* Use bms_prev_member(..., -1) to get the final member first and
* abort the loop when we go beyond that?
*/
- num_members = bms_num_members(cur_ec->ec_member_indexes);
+ final_member = bms_prev_member(cur_ec->ec_member_indexes, -1);
+
+ /*
+ * We consider only original EC members here, not
+ * already-transformed child members. Otherwise, if some original
+ * member expression references more than one appendrel, we'd get
+ * an O(N^2) explosion of useless derived expressions for
+ * combinations of children. (But add_child_join_rel_equivalences
+ * may add targeted combinations for partitionwise-join purposes.)
+ */
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, cur_ec);
j = -1;
- for (int pos = 0; pos < num_members; pos++)
+ while ((j = bms_next_member(matching_ems, j)) >= 0 && j <= final_member)
{
EquivalenceMember *cur_em;
-
- j = bms_next_member(cur_ec->ec_member_indexes, j);
cur_em = (EquivalenceMember *) list_nth(root->eq_members, j);
if (cur_em->em_is_const)
continue; /* ignore consts here */
- /*
- * We consider only original EC members here, not
- * already-transformed child members. Otherwise, if some original
- * member expression references more than one appendrel, we'd get
- * an O(N^2) explosion of useless derived expressions for
- * combinations of children. (But add_child_join_rel_equivalences
- * may add targeted combinations for partitionwise-join purposes.)
- */
- if (cur_em->em_is_child)
- continue; /* ignore children here */
+ Assert(!cur_em->em_is_child);
/* Does this member reference child's topmost parent rel? */
if (bms_overlap(cur_em->em_relids, top_parent_relids))
@@ -2780,8 +2818,9 @@ add_child_join_rel_equivalences(PlannerInfo *root,
while ((i = bms_next_member(matching_ecs, i)) >= 0)
{
EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
- int num_members;
+ int final_member;
int j;
+ Bitmapset *matching_ems;
/*
* If this EC contains a volatile expression, then generating child
@@ -2800,24 +2839,24 @@ add_child_join_rel_equivalences(PlannerInfo *root,
* Use bms_prev_member(..., -1) to get the final member first and
* abort the loop when we go beyond that?
*/
- num_members = bms_num_members(cur_ec->ec_member_indexes);
+ final_member = bms_prev_member(cur_ec->ec_member_indexes, -1);
+
+ /*
+ * We consider only original EC members here, not
+ * already-transformed child members.
+ */
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, cur_ec);
j = -1;
- for (int pos = 0; pos < num_members; pos++)
+ while ((j = bms_next_member(matching_ems, j)) >= 0 && j <= final_member)
{
EquivalenceMember *cur_em;
-
- j = bms_next_member(cur_ec->ec_member_indexes, j);
cur_em = (EquivalenceMember *) list_nth(root->eq_members, j);
if (cur_em->em_is_const)
continue; /* ignore consts here */
- /*
- * We consider only original EC members here, not
- * already-transformed child members.
- */
- if (cur_em->em_is_child)
- continue; /* ignore children here */
+ Assert(!cur_em->em_is_child);
/*
* We may ignore expressions that reference a single baserel,
@@ -2939,6 +2978,7 @@ generate_implied_equalities_for_column(PlannerInfo *root,
EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
EquivalenceMember *cur_em;
int j;
+ Bitmapset *matching_ems;
/* Sanity check eclass_indexes only contain ECs for rel */
Assert(is_child_rel || bms_is_subset(rel->relids, cur_ec->ec_relids));
@@ -2962,13 +3002,14 @@ generate_implied_equalities_for_column(PlannerInfo *root,
* match. See also get_eclass_for_sort_expr.)
*/
cur_em = NULL;
+ matching_ems = get_eclass_members_indexes_for_relids(root, cur_ec, rel);
j = -1;
- while ((j = bms_next_member(cur_ec->ec_member_indexes, j)) >= 0)
+ while ((j = bms_next_member(matching_ems, j)) >= 0)
{
cur_em = (EquivalenceMember *) list_nth(root->eq_members, j);
- if (bms_equal(cur_em->em_relids, rel->relids) &&
- callback(root, rel, cur_ec, cur_em, callback_arg))
+ Assert(bms_equal(cur_em->em_relids, rel->relids));
+ if (callback(root, rel, cur_ec, cur_em, callback_arg))
break;
cur_em = NULL;
}
@@ -2981,14 +3022,15 @@ generate_implied_equalities_for_column(PlannerInfo *root,
* joinclauses.
*/
j = -1;
- while ((j = bms_next_member(cur_ec->ec_member_indexes, j)) >= 0)
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, cur_ec);
+ while ((j = bms_next_member(matching_ems, j)) >= 0)
{
EquivalenceMember *other_em = (EquivalenceMember *) list_nth(root->eq_members, j);
Oid eq_op;
RestrictInfo *rinfo;
- if (other_em->em_is_child)
- continue; /* ignore children here */
+ Assert(!other_em->em_is_child);
/* Make sure it'll be a join to a different rel */
if (other_em == cur_em ||
@@ -3161,6 +3203,7 @@ eclass_useful_for_merging(PlannerInfo *root,
{
Relids relids;
int i;
+ Bitmapset *matching_ems;
Assert(!eclass->ec_merged);
@@ -3192,13 +3235,14 @@ eclass_useful_for_merging(PlannerInfo *root,
return false;
/* To join, we need a member not in the given rel */
+ /* ignore children here */
+ matching_ems = get_eclass_members_indexes_for_not_children(root, eclass);
i = -1;
- while ((i = bms_next_member(eclass->ec_member_indexes, i)) >= 0)
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *cur_em = (EquivalenceMember *) list_nth(root->eq_members, i);
- if (cur_em->em_is_child)
- continue; /* ignore children here */
+ Assert(!cur_em->em_is_child);
if (!bms_overlap(cur_em->em_relids, relids))
return true;
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 4c18ada572..843b7c7be3 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -3093,6 +3093,7 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index,
PathKey *pathkey = (PathKey *) lfirst(lc1);
bool found = false;
int i;
+ Bitmapset *matching_ems;
/*
* Note: for any failure to match, we just return NIL immediately.
@@ -3117,14 +3118,15 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index,
* here. See also get_eclass_for_sort_expr.)
*/
i = -1;
- while ((i = bms_next_member(pathkey->pk_eclass->ec_member_indexes, i)) >= 0)
+ /* No possibility of match if it references other relations */
+ matching_ems =
+ get_eclass_members_indexes_for_relids(root, pathkey->pk_eclass, index->rel);
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *member = (EquivalenceMember *) list_nth(root->eq_members, i);
int indexcol;
- /* No possibility of match if it references other relations */
- if (!bms_equal(member->em_relids, index->rel->relids))
- continue;
+ Assert(bms_equal(member->em_relids, index->rel->relids));
/*
* We allow any column of the index to match each pathkey; they
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index de864023b2..6fcf0ccb01 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -212,7 +212,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
bool reverse_sort,
bool nulls_first,
Index sortref,
- Relids rel,
+ RelOptInfo *rel,
bool create_it)
{
int16 strategy;
@@ -1134,7 +1134,7 @@ build_index_pathkeys(PlannerInfo *root,
reverse_sort,
nulls_first,
0,
- index->rel->relids,
+ index->rel,
false);
if (cpathkey)
@@ -1290,7 +1290,7 @@ build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
ScanDirectionIsBackward(scandir),
ScanDirectionIsBackward(scandir),
0,
- partrel->relids,
+ partrel,
false);
@@ -1343,7 +1343,7 @@ build_expression_pathkey(PlannerInfo *root,
Expr *expr,
Relids nullable_relids,
Oid opno,
- Relids rel,
+ RelOptInfo *rel,
bool create_it)
{
List *pathkeys;
@@ -1455,7 +1455,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
sub_member->em_datatype,
sub_eclass->ec_collation,
0,
- rel->relids,
+ rel,
false);
/*
@@ -1491,8 +1491,11 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
*/
int best_score = -1;
int j = -1;
+ /* ignore children here */
+ Bitmapset *matching_ems =
+ get_eclass_members_indexes_for_not_children(rel->subroot, sub_eclass);
- while ((j = bms_next_member(sub_eclass->ec_member_indexes, j)) >= 0)
+ while ((j = bms_next_member(matching_ems, j)) >= 0)
{
EquivalenceMember *sub_member = (EquivalenceMember *) list_nth(rel->subroot->eq_members, j);
Expr *sub_expr = sub_member->em_expr;
@@ -1500,8 +1503,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
Oid sub_expr_coll = sub_eclass->ec_collation;
ListCell *k;
- if (sub_member->em_is_child)
- continue; /* ignore children here */
+ Assert(!sub_member->em_is_child);
foreach(k, subquery_tlist)
{
@@ -1537,7 +1539,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
sub_expr_type,
sub_expr_coll,
0,
- rel->relids,
+ rel,
false);
/*
@@ -1966,6 +1968,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
EquivalenceClass *oeclass;
int score;
int i;
+ Bitmapset *matching_ems;
/* get the outer eclass */
update_mergeclause_eclasses(root, rinfo);
@@ -1987,12 +1990,14 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
/* compute score */
score = 0;
i = -1;
- while ((i = bms_next_member(oeclass->ec_member_indexes, i)) >= 0)
+ matching_ems = get_eclass_members_indexes_for_not_children(root, oeclass);
+ while ((i = bms_next_member(matching_ems, i)) >= 0)
{
EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+ Assert(!em->em_is_child);
/* Potential future join partner? */
- if (!em->em_is_const && !em->em_is_child &&
+ if (!em->em_is_const &&
!bms_overlap(em->em_relids, joinrel->relids))
score++;
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index d0bc9a467d..e71f115fd6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -620,6 +620,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->multiexpr_params = NIL;
root->eq_classes = NIL;
root->eq_members = NIL;
+ root->eq_not_children_indexes = NULL;
+ root->eq_empty_relids_indexes = NULL;
root->ec_merging_done = false;
root->all_result_relids =
parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL;
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index f3e6c19fc7..90a5dcae72 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -999,6 +999,8 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->multiexpr_params = NIL;
subroot->eq_classes = NIL;
subroot->eq_members = NIL;
+ subroot->eq_not_children_indexes = NULL;
+ subroot->eq_empty_relids_indexes = NULL;
subroot->ec_merging_done = false;
subroot->all_result_relids = NULL;
subroot->leaf_result_relids = NULL;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 520409f4ba..101742959a 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -231,6 +231,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->tuples = 0;
rel->allvisfrac = 0;
rel->eclass_indexes = NULL;
+ rel->eclass_member_indexes = NULL;
+ rel->eclass_referencing_member_indexes = NULL;
rel->subroot = NULL;
rel->subplan_params = NIL;
rel->rel_parallel_workers = -1; /* set up in get_relation_info */
@@ -645,6 +647,8 @@ build_join_rel(PlannerInfo *root,
joinrel->tuples = 0;
joinrel->allvisfrac = 0;
joinrel->eclass_indexes = NULL;
+ joinrel->eclass_member_indexes = NULL;
+ joinrel->eclass_referencing_member_indexes = NULL;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;
joinrel->rel_parallel_workers = -1;
@@ -828,6 +832,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->tuples = 0;
joinrel->allvisfrac = 0;
joinrel->eclass_indexes = NULL;
+ joinrel->eclass_member_indexes = NULL;
+ joinrel->eclass_referencing_member_indexes = NULL;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;
joinrel->amflags = 0;
@@ -1242,6 +1248,8 @@ fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
upperrel->cheapest_total_path = NULL;
upperrel->cheapest_unique_path = NULL;
upperrel->cheapest_parameterized_paths = NIL;
+ upperrel->eclass_member_indexes = NULL; /* TODO: Is this necessary? */
+ upperrel->eclass_referencing_member_indexes = NULL; /* TODO: Is this necessary? */
root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 34f2f39012..1cc23eec09 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -303,6 +303,12 @@ struct PlannerInfo
/* list of each EquivalenceMember */
List *eq_members;
+ /* indexes of EquivalenceMembers which are not children */
+ Bitmapset *eq_not_children_indexes;
+
+ /* indexes of EquivalenceMembers whose relids are empty */
+ Bitmapset *eq_empty_relids_indexes;
+
/* set true once ECs are canonical */
bool ec_merging_done;
@@ -891,6 +897,12 @@ typedef struct RelOptInfo
*/
Bitmapset *eclass_member_indexes;
+ /*
+ * Indexes in PlannerInfo's eq_members list of EMs that reference this rel
+ * TODO: Its variable name should be more refined.
+ */
+ Bitmapset *eclass_referencing_member_indexes;
+
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
/* wanted number of parallel workers */
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index c9482f86cb..d9dff21c1e 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -134,7 +134,7 @@ extern EquivalenceClass *get_eclass_for_sort_expr(PlannerInfo *root,
Oid opcintype,
Oid collation,
Index sortref,
- Relids rel,
+ RelOptInfo *rel,
bool create_it);
extern EquivalenceMember *find_ec_member_matching_expr(PlannerInfo *root,
EquivalenceClass *ec,
@@ -189,6 +189,154 @@ extern bool is_redundant_derived_clause(RestrictInfo *rinfo, List *clauselist);
extern bool is_redundant_with_indexclauses(RestrictInfo *rinfo,
List *indexclauses);
+/*
+ * TODO: The following helper functions are placed in this header file to help
+ * compiler inline them.
+ */
+
+/*
+ * get_eclass_members_indexes_for_relids
+ * Build and return a Bitmapset containing the indexes into root's
+ * eq_members list for all EquivalenceMembers whose em_relids is equal to
+ * the given RelOptInfo's relids
+ */
+static inline Bitmapset *
+get_eclass_members_indexes_for_relids(PlannerInfo *root,
+ EquivalenceClass *ec,
+ RelOptInfo *rel)
+{
+ if (rel == NULL)
+ return bms_intersect(ec->ec_member_indexes, root->eq_empty_relids_indexes);
+ else
+ return bms_intersect(ec->ec_member_indexes, rel->eclass_member_indexes);
+}
+
+/*
+ * get_eclass_members_indexes_for_not_children
+ * Build and return a Bitmapset containing the indexes into root's
+ * eq_members list for all EquivalenceMembers whose em_is_child is false
+ */
+static inline Bitmapset *
+get_eclass_members_indexes_for_not_children(PlannerInfo *root, EquivalenceClass *ec)
+{
+ return bms_intersect(ec->ec_member_indexes, root->eq_not_children_indexes);
+}
+
+/*
+ * get_eclass_members_indexes_for_relids_or_not_children
+ * Build and return a Bitmapset containing the indexes into root's
+ * eq_members list for all EquivalenceMembers whose em_relids is equal to
+ * the given RelOptInfo's relids, or em_is_child is false
+ */
+static inline Bitmapset *
+get_eclass_members_indexes_for_relids_or_not_children(PlannerInfo *root,
+ EquivalenceClass *ec,
+ RelOptInfo *rel)
+{
+ Bitmapset *em_indexes;
+
+ if (rel == NULL)
+ em_indexes = bms_union(root->eq_not_children_indexes, root->eq_empty_relids_indexes);
+ else
+ em_indexes = bms_union(root->eq_not_children_indexes, rel->eclass_member_indexes);
+
+ em_indexes = bms_int_members(em_indexes, ec->ec_member_indexes);
+
+ return em_indexes;
+}
+
+/*
+ * get_eclass_members_indexes_for_subsets_of_relids
+ * Build and return a Bitmapset containing the indexes into root's
+ * eq_members list for all EquivalenceMembers whose em_relids is a subset
+ * of the given relids
+ */
+static inline Bitmapset *
+get_eclass_members_indexes_for_subsets_of_relids(PlannerInfo *root,
+ EquivalenceClass *ec,
+ Relids relids)
+{
+ Bitmapset *em_indexes;
+ int i;
+
+ if (relids == NULL)
+ return bms_intersect(ec->ec_member_indexes, root->eq_empty_relids_indexes);
+
+ em_indexes = NULL;
+ i = -1;
+ while ((i = bms_next_member(relids, i)) >= 0)
+ {
+ RelOptInfo *rel = root->simple_rel_array[i];
+
+ /* Retrieve candidates that we want to get */
+ Bitmapset *em_candidates = bms_intersect(ec->ec_member_indexes,
+ rel->eclass_referencing_member_indexes);
+ int j;
+
+ /* Check if the candidates satisfy the condition */
+ j = -1;
+ while ((j = bms_next_member(em_candidates, j)) >= 0)
+ {
+ EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
+
+ if (bms_is_subset(em->em_relids, relids))
+ {
+ /* Satisfies, so add it to the result Bitmapset */
+ em_indexes = bms_add_member(em_indexes, j);
+ }
+ }
+ }
+
+ return em_indexes;
+}
+
+/*
+ * get_eclass_members_indexes_for_subsets_of_relids_or_not_children
+ * Build and return a Bitmapset containing the indexes into root's
+ * eq_members list for all EquivalenceMembers whose em_relids is a subset
+ * of the given relids, or em_is_child is false
+ */
+static inline Bitmapset *
+get_eclass_members_indexes_for_subsets_of_relids_or_not_children(PlannerInfo *root,
+ EquivalenceClass *ec,
+ Relids relids)
+{
+ Bitmapset *em_indexes;
+ int i;
+
+ if (relids == NULL)
+ return bms_int_members(bms_union(root->eq_empty_relids_indexes,
+ root->eq_not_children_indexes),
+ ec->ec_member_indexes);
+
+ em_indexes = bms_intersect(ec->ec_member_indexes, root->eq_not_children_indexes);
+ i = -1;
+ while ((i = bms_next_member(relids, i)) >= 0)
+ {
+ RelOptInfo *rel = root->simple_rel_array[i];
+
+ /* Retrieve candidates that we want to get */
+ Bitmapset *em_candidates = bms_intersect(ec->ec_member_indexes,
+ rel->eclass_referencing_member_indexes);
+ int j;
+
+ /* Check if the candidates satisfy the condition */
+ j = -1;
+ while ((j = bms_next_member(em_candidates, j)) >= 0)
+ {
+ EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
+
+ if (bms_is_subset(em->em_relids, relids))
+ {
+ /* Satisfies, so add it to the result Bitmapset */
+ em_indexes = bms_add_member(em_indexes, j);
+ }
+ }
+ }
+
+ return em_indexes;
+}
+
/*
* pathkeys.c
* utilities for matching and building path keys
@@ -226,7 +374,7 @@ extern List *build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
ScanDirection scandir, bool *partialkeys);
extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr,
Relids nullable_relids, Oid opno,
- Relids rel, bool create_it);
+ RelOptInfo *rel, bool create_it);
extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
List *subquery_pathkeys,
List *subquery_tlist);
--
2.35.3.windows.1