Evan Carroll Asked: 2021-11-03 16:11:22 +0800 CST2021-11-03 16:11:22 +0800 CST 2021-11-03 16:11:22 +0800 CST 什么是 SFRM_Materialize_Preferred 以及如何使用它来编写性能更高的函数? 772 研究这个问题,我看到 call 有一个SetFunctionReturnMode值SFRM_Materialize_Preferred。这是什么?这可以用来编写性能更高的函数吗? 有多次出现SRFM_Materializeincontrib/但没有SRFM_Materalize_Preferred postgresql postgresql-extensions 1 个回答 Voted Best Answer Evan Carroll 2021-11-03T16:11:56+08:002021-11-03T16:11:56+08:00 SFRM_Materialize_Preferred 允许您编写一个函数,该函数接受来自调用者的提示,该提示可以从自述文件中的文档Materialize接受或ValuePerCall模式 可以同时支持ValuePerCall和Materialize模式的调用者将SFRM_Materialize_Preferred根据他们喜欢的模式设置或不设置。 这在源代码中被记录为提示- 对 - 的扩展,SFRM_Materialize SFRM_Materialize_Random并且SFRM_Materialize_Preferred是关于模式的辅助标志SFRM_Materialize,而不是单独的模式。 您还可以看到这用于 SQL 的 PostgreSQL 函数管理器代码fmgr_sql lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred); 我自己的示范 SFRM_Materialize_Preferred为了对其进行基准测试,我创建了自己的非常简化的演示。你可以在我的 repo 中看到我的pg-srf-repeat. 基本上模板归结为这一点, Datum myfunc(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(myfunc); typedef struct { ; your function state only used in value-per-call mode } myfunc_fctx; Datum myfunc(PG_FUNCTION_ARGS) { ; get variables if (SRF_IS_FIRSTCALL()) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; // If we prefer materialize, get it done if ( rsinfo->allowedModes & SFRM_Materialize_Preferred ) { MemoryContext per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; MemoryContext oldcontext = MemoryContextSwitchTo(per_query_ctx); Tuplestorestate *tupstore = tuplestore_begin_heap(false, false, work_mem); rsinfo->setResult = tupstore; rsinfo->returnMode = SFRM_Materialize; TupleDesc tupdesc = rsinfo->expectedDesc; Datum values[1] = { ;stuff }; bool nulls[sizeof(values)] = {0}; # no nulls while ( times-- ) { tuplestore_putvalues(tupstore, tupdesc, values, nulls); } tuplestore_donestoring(tupstore); MemoryContextSwitchTo(oldcontext); PG_RETURN_NULL(); } // Initialize for multicall else { FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); myfunc_fctx *fctx = (myfunc_fctx *) palloc(sizeof(myfunc_fctx)); # set myfunc_fctx funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } } FuncCallContext *funcctx = SRF_PERCALL_SETUP(); myfunc_fctx *fctx = funcctx->user_fctx; # Call this SRF_RETURN_NEXT(funcctx, fctx->object); # Or this, SRF_RETURN_DONE(funcctx); } 这通常似乎执行更快的MaterializeorValuePerCall并且实现的开销很小(与纯实现相比)。 在 Pg-Python 中 由于相关信息的整体稀缺性,我在这里保持这一点。我已经确定这个宏SRF_SHOULD_MATERIALIZE案例实际上非常愚蠢(我已经打开了一个问题);宏的问题是并且始终是正确SRF_SHOULD_MATERIALIZESFRM_MaterializeSFRM_ValuePerCall的,因此本质上它只是SFRM_Materialize_Preferred**的较慢版本 它似乎也用于pg-python允许您从 PostgreSQL Functions 访问 Python 3 的项目中,但害羞的是,在所有 GitHub 上确实没有用例。for的pg-python宏SRF_SHOULD_MATERIALIZE如下(见上注) #define SRF_SHOULD_MATERIALIZE(FCINFO) ( ( ((ReturnSetInfo *) FCINFO->resultinfo)->allowedModes & SFRM_Materialize ) && ( !( ((ReturnSetInfo *) FCINFO->resultinfo)->allowedModes & SFRM_ValuePerCall ) || (( ((ReturnSetInfo *) FCINFO->resultinfo)->allowedModes & SFRM_Materialize_Preferred )) ) ) 您可以SRF_SHOULD_MATERIALIZE在调用站点看到使用过一次的宏
SFRM_Materialize_Preferred
允许您编写一个函数,该函数接受来自调用者的提示,该提示可以从自述文件中的文档Materialize
接受或ValuePerCall
模式这在源代码中被记录为提示- 对 - 的扩展,
SFRM_Materialize
您还可以看到这用于 SQL 的 PostgreSQL 函数管理器代码
fmgr_sql
我自己的示范
SFRM_Materialize_Preferred
为了对其进行基准测试,我创建了自己的非常简化的演示。你可以在我的 repo 中看到我的pg-srf-repeat
. 基本上模板归结为这一点,这通常似乎执行更快的
Materialize
orValuePerCall
并且实现的开销很小(与纯实现相比)。在 Pg-Python 中
由于相关信息的整体稀缺性,我在这里保持这一点。我已经确定这个宏
SRF_SHOULD_MATERIALIZE
案例实际上非常愚蠢(我已经打开了一个问题);宏的问题是并且始终是正确SRF_SHOULD_MATERIALIZE
SFRM_Materialize
SFRM_ValuePerCall
的,因此本质上它只是SFRM_Materialize_Preferred
**的较慢版本它似乎也用于
pg-python
允许您从 PostgreSQL Functions 访问 Python 3 的项目中,但害羞的是,在所有 GitHub 上确实没有用例。for的pg-python
宏SRF_SHOULD_MATERIALIZE
如下(见上注)您可以
SRF_SHOULD_MATERIALIZE
在调用站点看到使用过一次的宏