Skip to content

Commit a911013

Browse files
committed
Remember pathkey's source expression.
To consistently estimate the number of groups using the pathkeys list in the sorting operation, we need to identify the expression used as a sort key. Pathkey refers to the equivalence class, which can contain a wide variety of expressions. To somehow stabilise the expression's choice, save the link to the origin expression, triggering the PathKey creation. While this approach doesn't always guarantee the right choice, it makes dependence on the SQL string less obvious.
1 parent 4058c72 commit a911013

File tree

5 files changed

+59
-13
lines changed

5 files changed

+59
-13
lines changed

contrib/postgres_fdw/postgres_fdw.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,7 @@ get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
976976
foreach(lc, useful_eclass_list)
977977
{
978978
EquivalenceClass *cur_ec = lfirst(lc);
979+
EquivalenceMember *em;
979980
PathKey *pathkey;
980981

981982
/* If redundant with what we did above, skip it. */
@@ -988,14 +989,15 @@ get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
988989
continue;
989990

990991
/* If no pushable expression for this rel, skip it. */
991-
if (find_em_for_rel(root, cur_ec, rel) == NULL)
992+
if ((em = find_em_for_rel(root, cur_ec, rel)) == NULL)
992993
continue;
993994

994995
/* Looks like we can generate a pathkey, so let's do it. */
995996
pathkey = make_canonical_pathkey(root, cur_ec,
996997
linitial_oid(cur_ec->ec_opfamilies),
997998
BTLessStrategyNumber,
998-
false);
999+
false,
1000+
em->em_expr); /* TODO */
9991001
useful_pathkeys_list = lappend(useful_pathkeys_list,
10001002
list_make1(pathkey));
10011003
}

src/backend/optimizer/path/costsize.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,21 +2019,41 @@ cost_incremental_sort(Path *path,
20192019
foreach(l, pathkeys)
20202020
{
20212021
PathKey *key = (PathKey *) lfirst(l);
2022-
EquivalenceMember *member = (EquivalenceMember *)
2023-
linitial(key->pk_eclass->ec_members);
2022+
2023+
#ifdef USE_ASSERT_CHECKING
2024+
ListCell *lc;
2025+
2026+
/* Be paranoid, but caring about performace don't check on prod */
2027+
foreach(lc, key->pk_eclass->ec_members)
2028+
{
2029+
if (find_ec_member_matching_expr(
2030+
key->pk_eclass, key->source_expr,
2031+
pull_varnos(root, (Node *) key->source_expr)))
2032+
break;
2033+
}
2034+
if (!lc)
2035+
/*
2036+
* XXX: Can we build PathKey over derived expression and does it
2037+
* trigger this error?
2038+
*/
2039+
elog(ERROR, "PathKey source expression must be a part of EQ class");
2040+
#endif
2041+
2042+
/* Reassure ourselves no one created pathkeys alternative way */
2043+
Assert(key->source_expr != NULL);
20242044

20252045
/*
20262046
* Check if the expression contains Var with "varno 0" so that we
20272047
* don't call estimate_num_groups in that case.
20282048
*/
2029-
if (bms_is_member(0, pull_varnos(root, (Node *) member->em_expr)))
2049+
if (bms_is_member(0, pull_varnos(root, (Node *) key->source_expr)))
20302050
{
20312051
unknown_varno = true;
20322052
break;
20332053
}
20342054

20352055
/* expression not containing any Vars with "varno 0" */
2036-
presortedExprs = lappend(presortedExprs, member->em_expr);
2056+
presortedExprs = lappend(presortedExprs, key->source_expr);
20372057

20382058
if (foreach_current_index(l) + 1 >= presorted_keys)
20392059
break;

src/backend/optimizer/path/pathkeys.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
5454
PathKey *
5555
make_canonical_pathkey(PlannerInfo *root,
5656
EquivalenceClass *eclass, Oid opfamily,
57-
int strategy, bool nulls_first)
57+
int strategy, bool nulls_first, Expr *src_expr)
5858
{
5959
PathKey *pk;
6060
ListCell *lc;
@@ -89,6 +89,7 @@ make_canonical_pathkey(PlannerInfo *root,
8989
pk->pk_opfamily = opfamily;
9090
pk->pk_strategy = strategy;
9191
pk->pk_nulls_first = nulls_first;
92+
pk->source_expr = src_expr;
9293

9394
root->canon_pathkeys = lappend(root->canon_pathkeys, pk);
9495

@@ -241,7 +242,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
241242

242243
/* And finally we can find or create a PathKey node */
243244
return make_canonical_pathkey(root, eclass, opfamily,
244-
strategy, nulls_first);
245+
strategy, nulls_first, expr);
245246
}
246247

247248
/*
@@ -1117,7 +1118,8 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
11171118
outer_ec,
11181119
sub_pathkey->pk_opfamily,
11191120
sub_pathkey->pk_strategy,
1120-
sub_pathkey->pk_nulls_first);
1121+
sub_pathkey->pk_nulls_first,
1122+
(Expr *) outer_var);
11211123
}
11221124
}
11231125
else
@@ -1199,7 +1201,8 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
11991201
outer_ec,
12001202
sub_pathkey->pk_opfamily,
12011203
sub_pathkey->pk_strategy,
1202-
sub_pathkey->pk_nulls_first);
1204+
sub_pathkey->pk_nulls_first,
1205+
(Expr *) outer_var);
12031206
/* score = # of equivalence peers */
12041207
score = list_length(outer_ec->ec_members) - 1;
12051208
/* +1 if it matches the proper query_pathkeys item */
@@ -1646,6 +1649,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
16461649
List *pathkeys = NIL;
16471650
int nClauses = list_length(mergeclauses);
16481651
EquivalenceClass **ecs;
1652+
Expr **exprs;
16491653
int *scores;
16501654
int necs;
16511655
ListCell *lc;
@@ -1660,6 +1664,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
16601664
* duplicates) and their "popularity" scores.
16611665
*/
16621666
ecs = (EquivalenceClass **) palloc(nClauses * sizeof(EquivalenceClass *));
1667+
exprs = (Expr **) palloc(nClauses * sizeof(Expr *));
16631668
scores = (int *) palloc(nClauses * sizeof(int));
16641669
necs = 0;
16651670

@@ -1669,14 +1674,21 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
16691674
EquivalenceClass *oeclass;
16701675
int score;
16711676
ListCell *lc2;
1677+
Expr *expr;
16721678

16731679
/* get the outer eclass */
16741680
update_mergeclause_eclasses(root, rinfo);
16751681

16761682
if (rinfo->outer_is_left)
1683+
{
16771684
oeclass = rinfo->left_ec;
1685+
expr = (Expr *) linitial(((OpExpr *) rinfo->clause)->args);
1686+
}
16781687
else
1688+
{
16791689
oeclass = rinfo->right_ec;
1690+
expr = (Expr *) lsecond(((OpExpr *) rinfo->clause)->args);
1691+
}
16801692

16811693
/* reject duplicates */
16821694
for (j = 0; j < necs; j++)
@@ -1700,6 +1712,8 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
17001712
}
17011713

17021714
ecs[necs] = oeclass;
1715+
exprs[necs] = expr;
1716+
17031717
scores[necs] = score;
17041718
necs++;
17051719
}
@@ -1801,7 +1815,8 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
18011815
ec,
18021816
linitial_oid(ec->ec_opfamilies),
18031817
BTLessStrategyNumber,
1804-
false);
1818+
false,
1819+
exprs[best_j]);
18051820
/* can't be redundant because no duplicate ECs */
18061821
Assert(!pathkey_is_redundant(pathkey, pathkeys));
18071822
pathkeys = lappend(pathkeys, pathkey);
@@ -1855,18 +1870,23 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
18551870
EquivalenceClass *oeclass;
18561871
EquivalenceClass *ieclass;
18571872
PathKey *pathkey;
1873+
Expr *src_expr;
18581874

18591875
update_mergeclause_eclasses(root, rinfo);
18601876

1877+
Assert(IsA(rinfo->clause, OpExpr) && rinfo->orclause == NULL);
1878+
18611879
if (rinfo->outer_is_left)
18621880
{
18631881
oeclass = rinfo->left_ec;
18641882
ieclass = rinfo->right_ec;
1883+
src_expr = (Expr *) lsecond(((OpExpr *) rinfo->clause)->args);
18651884
}
18661885
else
18671886
{
18681887
oeclass = rinfo->right_ec;
18691888
ieclass = rinfo->left_ec;
1889+
src_expr = (Expr *) linitial(((OpExpr *) rinfo->clause)->args);
18701890
}
18711891

18721892
/* outer eclass should match current or next pathkeys */
@@ -1894,7 +1914,8 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
18941914
ieclass,
18951915
opathkey->pk_opfamily,
18961916
opathkey->pk_strategy,
1897-
opathkey->pk_nulls_first);
1917+
opathkey->pk_nulls_first,
1918+
src_expr);
18981919

18991920
/*
19001921
* Don't generate redundant pathkeys (which can happen if multiple

src/include/nodes/pathnodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,8 @@ typedef struct PathKey
14691469
Oid pk_opfamily; /* btree opfamily defining the ordering */
14701470
int pk_strategy; /* sort direction (ASC or DESC) */
14711471
bool pk_nulls_first; /* do NULLs come before normal values? */
1472+
1473+
Expr *source_expr; /* Expression, which triggered this creation */
14721474
} PathKey;
14731475

14741476
/*

src/include/optimizer/paths.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ extern bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel);
264264
extern List *append_pathkeys(List *target, List *source);
265265
extern PathKey *make_canonical_pathkey(PlannerInfo *root,
266266
EquivalenceClass *eclass, Oid opfamily,
267-
int strategy, bool nulls_first);
267+
int strategy, bool nulls_first,
268+
Expr *src_expr);
268269
extern void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
269270
List *live_childrels);
270271

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy