From c32a5139e4535313f20a23345fdca17d18298228 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 9 Nov 2026 11:19:43 +1300 Subject: [PATCH v1 2/2] Don't build unused Memoize hash and equality state in binary mode When a Memoize node is in binary mode, cache keys are hashed with datum_image_hash() and compared with datum_image_eq(). Despite that, ExecInitMemoize() always looked up the hash functions for each cache key and built cache_eq_expr, neither of which binary mode uses. Only do that work when not in binary mode. This saves some executor startup work and memory for Memoize nodes using binary mode. Author: David Rowley --- src/backend/executor/nodeMemoize.c | 67 ++++++++++++++++++------------ 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c index 023468e056c..5de7c613cd8 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -1038,39 +1038,58 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags) mstate->probeslot = MakeSingleTupleTableSlot(mstate->hashkeydesc, &TTSOpsVirtual); + /* + * Record if the cache keys should be compared bit by bit, or logically + * using the type's hash equality operator + */ + mstate->binary_mode = node->binary_mode; + mstate->param_exprs = palloc_array(ExprState *, nkeys); mstate->collations = node->collations; /* Just point directly to the plan * data */ - mstate->hashfunctions = palloc_array(FmgrInfo, nkeys); - - eqfuncoids = palloc_array(Oid, nkeys); for (i = 0; i < nkeys; i++) { - Oid hashop = node->hashOperators[i]; - Oid left_hashfn; - Oid right_hashfn; Expr *param_expr = (Expr *) list_nth(node->param_exprs, i); - if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn)) - elog(ERROR, "could not find hash function for hash operator %u", - hashop); - - fmgr_info(left_hashfn, &mstate->hashfunctions[i]); - mstate->param_exprs[i] = ExecInitExpr(param_expr, (PlanState *) mstate); - eqfuncoids[i] = get_opcode(hashop); } - mstate->cache_eq_expr = ExecBuildParamSetEqual(mstate->hashkeydesc, - &TTSOpsMinimalTuple, - &TTSOpsVirtual, - eqfuncoids, - node->collations, - node->param_exprs, - (PlanState *) mstate); + /* + * In binary mode, the cache keys are hashed and compared using + * datum_image_hash() and datum_image_eq(), so the hash functions and + * equality expression are only needed when not in binary mode. + */ + if (!mstate->binary_mode) + { + mstate->hashfunctions = palloc_array(FmgrInfo, nkeys); + eqfuncoids = palloc_array(Oid, nkeys); + + for (i = 0; i < nkeys; i++) + { + Oid hashop = node->hashOperators[i]; + Oid left_hashfn; + Oid right_hashfn; + + if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn)) + elog(ERROR, "could not find hash function for hash operator %u", + hashop); + + fmgr_info(left_hashfn, &mstate->hashfunctions[i]); + eqfuncoids[i] = get_opcode(hashop); + } + + mstate->cache_eq_expr = ExecBuildParamSetEqual(mstate->hashkeydesc, + &TTSOpsMinimalTuple, + &TTSOpsVirtual, + eqfuncoids, + node->collations, + node->param_exprs, + (PlanState *) mstate); + + pfree(eqfuncoids); + } - pfree(eqfuncoids); mstate->mem_used = 0; /* Limit the total memory consumed by the cache to this */ @@ -1096,12 +1115,6 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags) mstate->singlerow = node->singlerow; mstate->keyparamids = node->keyparamids; - /* - * Record if the cache keys should be compared bit by bit, or logically - * using the type's hash equality operator - */ - mstate->binary_mode = node->binary_mode; - /* Zero the statistics counters */ memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation)); -- 2.53.0