Skip to content

Commit 69922ca

Browse files
Ilia EvdokimovCommitfest Bot
authored andcommitted
Expose cache hit statistics in Memoize node EXPLAIN output.
This patch adds additional information to the Memoize node's EXPLAIN output: estimated cache capacity, number of distinct keys, total lookups, and cache hit percentage.
1 parent 71c0921 commit 69922ca

File tree

7 files changed

+62
-12
lines changed

7 files changed

+62
-12
lines changed

src/backend/commands/explain.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3616,6 +3616,26 @@ show_memoize_info(MemoizeState *mstate, List *ancestors, ExplainState *es)
36163616
ExplainPropertyText("Cache Key", keystr.data, es);
36173617
ExplainPropertyText("Cache Mode", mstate->binary_mode ? "binary" : "logical", es);
36183618

3619+
if (es->costs)
3620+
{
3621+
if (es->format == EXPLAIN_FORMAT_TEXT)
3622+
{
3623+
ExplainIndentText(es);
3624+
appendStringInfo(es->str, "Estimates: capacity=%u distinct keys=%.0f lookups=%.0f hit percent=%.2f%%\n",
3625+
((Memoize *) plan)->est_entries,
3626+
((Memoize *) plan)->est_unique_keys,
3627+
((Memoize *) plan)->est_calls,
3628+
((Memoize *) plan)->est_hit_ratio * 100.0);
3629+
}
3630+
else
3631+
{
3632+
ExplainPropertyUInteger("Estimated Capacity", NULL, ((Memoize *) plan)->est_entries, es);
3633+
ExplainPropertyFloat("Estimated Distinct Lookup Keys", NULL, ((Memoize *) plan)->est_unique_keys, 0, es);
3634+
ExplainPropertyFloat("Estimated Lookups", NULL, ((Memoize *) plan)->est_calls, 0, es);
3635+
ExplainPropertyFloat("Estimated Hit Percent", NULL, ((Memoize *) plan)->est_hit_ratio * 100.0, 2, es);
3636+
}
3637+
}
3638+
36193639
pfree(keystr.data);
36203640

36213641
if (!es->analyze)

src/backend/optimizer/path/costsize.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,7 +2572,7 @@ cost_memoize_rescan(PlannerInfo *root, MemoizePath *mpath,
25722572
Cost input_startup_cost = mpath->subpath->startup_cost;
25732573
Cost input_total_cost = mpath->subpath->total_cost;
25742574
double tuples = mpath->subpath->rows;
2575-
double calls = mpath->calls;
2575+
double est_calls = mpath->est_calls;
25762576
int width = mpath->subpath->pathtarget->width;
25772577

25782578
double hash_mem_bytes;
@@ -2604,7 +2604,7 @@ cost_memoize_rescan(PlannerInfo *root, MemoizePath *mpath,
26042604
est_cache_entries = floor(hash_mem_bytes / est_entry_bytes);
26052605

26062606
/* estimate on the distinct number of parameter values */
2607-
ndistinct = estimate_num_groups(root, mpath->param_exprs, calls, NULL,
2607+
ndistinct = estimate_num_groups(root, mpath->param_exprs, est_calls, NULL,
26082608
&estinfo);
26092609

26102610
/*
@@ -2616,7 +2616,7 @@ cost_memoize_rescan(PlannerInfo *root, MemoizePath *mpath,
26162616
* certainly mean a MemoizePath will never survive add_path().
26172617
*/
26182618
if ((estinfo.flags & SELFLAG_USED_DEFAULT) != 0)
2619-
ndistinct = calls;
2619+
ndistinct = est_calls;
26202620

26212621
/*
26222622
* Since we've already estimated the maximum number of entries we can
@@ -2630,6 +2630,9 @@ cost_memoize_rescan(PlannerInfo *root, MemoizePath *mpath,
26302630
mpath->est_entries = Min(Min(ndistinct, est_cache_entries),
26312631
PG_UINT32_MAX);
26322632

2633+
/* Remember the ndistinct estimate for EXPLAIN */
2634+
mpath->est_unique_keys = ndistinct;
2635+
26332636
/*
26342637
* When the number of distinct parameter values is above the amount we can
26352638
* store in the cache, then we'll have to evict some entries from the
@@ -2644,9 +2647,12 @@ cost_memoize_rescan(PlannerInfo *root, MemoizePath *mpath,
26442647
* must look at how many scans are estimated in total for this node and
26452648
* how many of those scans we expect to get a cache hit.
26462649
*/
2647-
hit_ratio = ((calls - ndistinct) / calls) *
2650+
hit_ratio = ((est_calls - ndistinct) / est_calls) *
26482651
(est_cache_entries / Max(ndistinct, est_cache_entries));
26492652

2653+
/* Remember the hit ratio estimate for EXPLAIN */
2654+
mpath->est_hit_ratio = hit_ratio;
2655+
26502656
Assert(hit_ratio >= 0 && hit_ratio <= 1.0);
26512657

26522658
/*

src/backend/optimizer/plan/createplan.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ static Material *make_material(Plan *lefttree);
284284
static Memoize *make_memoize(Plan *lefttree, Oid *hashoperators,
285285
Oid *collations, List *param_exprs,
286286
bool singlerow, bool binary_mode,
287-
uint32 est_entries, Bitmapset *keyparamids);
287+
uint32 est_entries, Bitmapset *keyparamids,
288+
double est_calls, double est_unique_keys,
289+
double est_hit_ratio);
288290
static WindowAgg *make_windowagg(List *tlist, WindowClause *wc,
289291
int partNumCols, AttrNumber *partColIdx, Oid *partOperators, Oid *partCollations,
290292
int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
@@ -1753,7 +1755,8 @@ create_memoize_plan(PlannerInfo *root, MemoizePath *best_path, int flags)
17531755

17541756
plan = make_memoize(subplan, operators, collations, param_exprs,
17551757
best_path->singlerow, best_path->binary_mode,
1756-
best_path->est_entries, keyparamids);
1758+
best_path->est_entries, keyparamids, best_path->est_calls,
1759+
best_path->est_unique_keys, best_path->est_hit_ratio);
17571760

17581761
copy_generic_path_info(&plan->plan, (Path *) best_path);
17591762

@@ -6749,7 +6752,8 @@ materialize_finished_plan(Plan *subplan)
67496752
static Memoize *
67506753
make_memoize(Plan *lefttree, Oid *hashoperators, Oid *collations,
67516754
List *param_exprs, bool singlerow, bool binary_mode,
6752-
uint32 est_entries, Bitmapset *keyparamids)
6755+
uint32 est_entries, Bitmapset *keyparamids, double est_calls,
6756+
double est_unique_keys, double est_hit_ratio)
67536757
{
67546758
Memoize *node = makeNode(Memoize);
67556759
Plan *plan = &node->plan;
@@ -6767,6 +6771,9 @@ make_memoize(Plan *lefttree, Oid *hashoperators, Oid *collations,
67676771
node->binary_mode = binary_mode;
67686772
node->est_entries = est_entries;
67696773
node->keyparamids = keyparamids;
6774+
node->est_calls = est_calls;
6775+
node->est_unique_keys = est_unique_keys;
6776+
node->est_hit_ratio = est_hit_ratio;
67706777

67716778
return node;
67726779
}

src/backend/optimizer/util/pathnode.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
16891689
MemoizePath *
16901690
create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
16911691
List *param_exprs, List *hash_operators,
1692-
bool singlerow, bool binary_mode, double calls)
1692+
bool singlerow, bool binary_mode, double est_calls)
16931693
{
16941694
MemoizePath *pathnode = makeNode(MemoizePath);
16951695

@@ -1710,7 +1710,6 @@ create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
17101710
pathnode->param_exprs = param_exprs;
17111711
pathnode->singlerow = singlerow;
17121712
pathnode->binary_mode = binary_mode;
1713-
pathnode->calls = clamp_row_est(calls);
17141713

17151714
/*
17161715
* For now we set est_entries to 0. cost_memoize_rescan() does all the
@@ -1720,6 +1719,12 @@ create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
17201719
*/
17211720
pathnode->est_entries = 0;
17221721

1722+
pathnode->est_calls = clamp_row_est(est_calls);
1723+
1724+
/* These will also be set later in cost_memoize_rescan() */
1725+
pathnode->est_unique_keys = 0;
1726+
pathnode->est_hit_ratio = 0;
1727+
17231728
/* we should not generate this path type when enable_memoize=false */
17241729
Assert(enable_memoize);
17251730
pathnode->path.disabled_nodes = subpath->disabled_nodes;
@@ -4259,7 +4264,7 @@ reparameterize_path(PlannerInfo *root, Path *path,
42594264
mpath->hash_operators,
42604265
mpath->singlerow,
42614266
mpath->binary_mode,
4262-
mpath->calls);
4267+
mpath->est_calls);
42634268
}
42644269
default:
42654270
break;

src/include/nodes/pathnodes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2133,10 +2133,12 @@ typedef struct MemoizePath
21332133
* complete after caching the first record. */
21342134
bool binary_mode; /* true when cache key should be compared bit
21352135
* by bit, false when using hash equality ops */
2136-
Cardinality calls; /* expected number of rescans */
21372136
uint32 est_entries; /* The maximum number of entries that the
21382137
* planner expects will fit in the cache, or 0
21392138
* if unknown */
2139+
Cardinality est_calls; /* expected number of rescans */
2140+
Cardinality est_unique_keys; /* estimated unique keys, for EXPLAIN */
2141+
double est_hit_ratio; /* estimated cache hit ratio, for EXPLAIN */
21402142
} MemoizePath;
21412143

21422144
/*

src/include/nodes/plannodes.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,16 @@ typedef struct Memoize
10731073

10741074
/* paramids from param_exprs */
10751075
Bitmapset *keyparamids;
1076+
1077+
/* Estimated number of rescans, for EXPLAIN */
1078+
Cardinality est_calls;
1079+
1080+
/* Estimated number of distinct lookup keys, for EXPLAIN */
1081+
Cardinality est_unique_keys;
1082+
1083+
/* Estimated cache hit ratio, for EXPLAIN */
1084+
double est_hit_ratio;
1085+
10761086
} Memoize;
10771087

10781088
/* ----------------

src/include/optimizer/pathnode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ extern MemoizePath *create_memoize_path(PlannerInfo *root,
9090
List *hash_operators,
9191
bool singlerow,
9292
bool binary_mode,
93-
double calls);
93+
double est_calls);
9494
extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
9595
Path *subpath, SpecialJoinInfo *sjinfo);
9696
extern GatherPath *create_gather_path(PlannerInfo *root,

0 commit comments

Comments
 (0)