Skip to content

Commit dc3648f

Browse files
committed
Fix Memoize to work with partitionwise joining.
A couple of places weren't up to speed for this. By sheer good luck, we didn't fail but just selected a non-memoized join plan, at least in the test case we have. Nonetheless, it's a bug, and I'm not quite sure that it couldn't have worse consequences in other examples. So back-patch to v14 where Memoize came in. Richard Guo Discussion: https://postgr.es/m/CAMbWs48GkNom272sfp0-WeD6_0HSR19BJ4H1c9ZKSfbVnJsvRg@mail.gmail.com
1 parent 1bd84ef commit dc3648f

File tree

5 files changed

+74
-3
lines changed

5 files changed

+74
-3
lines changed

src/backend/optimizer/path/joinpath.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ get_memoize_path(PlannerInfo *root, RelOptInfo *innerrel,
490490
Path *outer_path, JoinType jointype,
491491
JoinPathExtraData *extra)
492492
{
493+
RelOptInfo *top_outerrel;
493494
List *param_exprs;
494495
List *hash_operators;
495496
ListCell *lc;
@@ -579,10 +580,21 @@ get_memoize_path(PlannerInfo *root, RelOptInfo *innerrel,
579580
return NULL;
580581
}
581582

583+
/*
584+
* When considering a partitionwise join, we have clauses that reference
585+
* the outerrel's top parent not outerrel itself.
586+
*/
587+
if (outerrel->reloptkind == RELOPT_OTHER_MEMBER_REL)
588+
top_outerrel = find_base_rel(root, bms_singleton_member(outerrel->top_parent_relids));
589+
else if (outerrel->reloptkind == RELOPT_OTHER_JOINREL)
590+
top_outerrel = find_join_rel(root, outerrel->top_parent_relids);
591+
else
592+
top_outerrel = outerrel;
593+
582594
/* Check if we have hash ops for each parameter to the path */
583595
if (paraminfo_get_equal_hashops(root,
584596
inner_path->param_info,
585-
outerrel,
597+
top_outerrel,
586598
innerrel,
587599
&param_exprs,
588600
&hash_operators,

src/backend/optimizer/util/pathnode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,6 +4176,7 @@ do { \
41764176

41774177
FLAT_COPY_PATH(mpath, path, MemoizePath);
41784178
REPARAMETERIZE_CHILD_PATH(mpath->subpath);
4179+
ADJUST_CHILD_ATTRS(mpath->param_exprs);
41794180
new_path = (Path *) mpath;
41804181
}
41814182
break;

src/include/nodes/pathnodes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,8 +1508,8 @@ typedef struct MemoizePath
15081508
{
15091509
Path path;
15101510
Path *subpath; /* outerpath to cache tuples from */
1511-
List *hash_operators; /* hash operators for each key */
1512-
List *param_exprs; /* cache keys */
1511+
List *hash_operators; /* OIDs of hash equality ops for cache keys */
1512+
List *param_exprs; /* expressions that are cache keys */
15131513
bool singlerow; /* true if the cache entry is to be marked as
15141514
* complete after caching the first record. */
15151515
bool binary_mode; /* true when cache key should be compared bit

src/test/regress/expected/memoize.out

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,45 @@ SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.t >= s2.t;', false);
196196
(8 rows)
197197

198198
DROP TABLE strtest;
199+
-- Ensure memoize works with partitionwise join
200+
SET enable_partitionwise_join TO on;
201+
CREATE TABLE prt (a int) PARTITION BY RANGE(a);
202+
CREATE TABLE prt_p1 PARTITION OF prt FOR VALUES FROM (0) TO (10);
203+
CREATE TABLE prt_p2 PARTITION OF prt FOR VALUES FROM (10) TO (20);
204+
INSERT INTO prt VALUES (0), (0), (0), (0);
205+
INSERT INTO prt VALUES (10), (10), (10), (10);
206+
CREATE INDEX iprt_p1_a ON prt_p1 (a);
207+
CREATE INDEX iprt_p2_a ON prt_p2 (a);
208+
ANALYZE prt;
209+
SELECT explain_memoize('
210+
SELECT * FROM prt t1 INNER JOIN prt t2 ON t1.a = t2.a;', false);
211+
explain_memoize
212+
------------------------------------------------------------------------------------------
213+
Append (actual rows=32 loops=N)
214+
-> Nested Loop (actual rows=16 loops=N)
215+
-> Index Only Scan using iprt_p1_a on prt_p1 t1_1 (actual rows=4 loops=N)
216+
Heap Fetches: N
217+
-> Memoize (actual rows=4 loops=N)
218+
Cache Key: t1_1.a
219+
Cache Mode: logical
220+
Hits: 3 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
221+
-> Index Only Scan using iprt_p1_a on prt_p1 t2_1 (actual rows=4 loops=N)
222+
Index Cond: (a = t1_1.a)
223+
Heap Fetches: N
224+
-> Nested Loop (actual rows=16 loops=N)
225+
-> Index Only Scan using iprt_p2_a on prt_p2 t1_2 (actual rows=4 loops=N)
226+
Heap Fetches: N
227+
-> Memoize (actual rows=4 loops=N)
228+
Cache Key: t1_2.a
229+
Cache Mode: logical
230+
Hits: 3 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
231+
-> Index Only Scan using iprt_p2_a on prt_p2 t2_2 (actual rows=4 loops=N)
232+
Index Cond: (a = t1_2.a)
233+
Heap Fetches: N
234+
(21 rows)
235+
236+
DROP TABLE prt;
237+
RESET enable_partitionwise_join;
199238
-- Exercise Memoize code that flushes the cache when a parameter changes which
200239
-- is not part of the cache key.
201240
-- Ensure we get a Memoize plan

src/test/regress/sql/memoize.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,25 @@ SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.t >= s2.t;', false);
103103

104104
DROP TABLE strtest;
105105

106+
-- Ensure memoize works with partitionwise join
107+
SET enable_partitionwise_join TO on;
108+
109+
CREATE TABLE prt (a int) PARTITION BY RANGE(a);
110+
CREATE TABLE prt_p1 PARTITION OF prt FOR VALUES FROM (0) TO (10);
111+
CREATE TABLE prt_p2 PARTITION OF prt FOR VALUES FROM (10) TO (20);
112+
INSERT INTO prt VALUES (0), (0), (0), (0);
113+
INSERT INTO prt VALUES (10), (10), (10), (10);
114+
CREATE INDEX iprt_p1_a ON prt_p1 (a);
115+
CREATE INDEX iprt_p2_a ON prt_p2 (a);
116+
ANALYZE prt;
117+
118+
SELECT explain_memoize('
119+
SELECT * FROM prt t1 INNER JOIN prt t2 ON t1.a = t2.a;', false);
120+
121+
DROP TABLE prt;
122+
123+
RESET enable_partitionwise_join;
124+
106125
-- Exercise Memoize code that flushes the cache when a parameter changes which
107126
-- is not part of the cache key.
108127

0 commit comments

Comments
 (0)