如何检测新SQL语句开始执行?PLV8函数缓存刷新需求咨询
解决PLV8函数语句级缓存刷新的问题
针对你说的「单条SQL语句中多次调用高成本PLV8函数,想缓存结果但需要每次语句执行时刷新」的需求,有几个非常贴合的方案,而且完全避开了表变更触发的局限性:
方案1:用PLV8原生的语句级变量存储
PLV8本身支持语句作用域的变量,这类变量会在每次新SQL语句执行时自动清空,完美匹配你的需求。具体实现如下:
CREATE OR REPLACE FUNCTION expensive_calculation() RETURNS integer AS $$ // 定义缓存键名 const cacheKey = 'calc_expensive_result'; // 尝试从语句级缓存获取值 const cachedValue = plv8.get_variable(cacheKey, 'statement'); if (cachedValue === undefined) { // 这里放你的高成本计算逻辑 const result = /* 比如复杂的数据库查询、计算操作 */ 42; // 将结果存入语句级缓存 plv8.set_variable(cacheKey, result, 'statement'); return result; } // 缓存存在直接返回 return cachedValue; $$ LANGUAGE plv8;
这个方案的好处是完全在PLV8上下文内完成,不用切换到SQL层,性能更优,而且statement作用域的变量会自动在语句结束后释放,完全不用手动管理缓存清空。
方案2:借助PostgreSQL的SET LOCAL实现语句级状态
如果你更习惯用SQL层面的方式控制,PostgreSQL的SET LOCAL命令可以设置仅当前语句/事务生效的会话变量,单条SQL语句执行时,这个变量会在语句结束后自动失效:
CREATE OR REPLACE FUNCTION expensive_calculation() RETURNS integer AS $$ const cacheKey = 'my_expensive_calc_cache'; // 尝试获取当前语句的缓存变量 const res = plv8.execute(`SELECT current_setting('${cacheKey}', true) AS val`); const cachedVal = res[0].val; if (cachedVal === null) { // 执行高成本计算 const result = /* 你的计算逻辑 */ 42; // 用SET LOCAL设置语句级变量 plv8.execute(`SET LOCAL ${cacheKey} = ${result}`); return result; } return parseInt(cachedVal); $$ LANGUAGE plv8;
需要注意:如果是在一个多语句事务中,SET LOCAL的变量会持续到事务结束;但如果是单条SQL语句(比如单独的SELECT),变量会在语句执行完成后自动重置,刚好符合你的场景。
为什么这两个方案能解决你的痛点?
- 完全避开了表触发的问题:不管其他连接怎么修改数据库,当前连接每次执行新的SQL语句时,缓存都会自动清空,重新计算基于当前语句的数据库快照(PostgreSQL的快照隔离特性保证了每个语句看到的是执行开始时的一致数据)。
- 单语句内多次调用会复用缓存:比如你在SELECT的多行结果中调用这个函数,只会计算一次,后续调用直接用缓存,大幅降低计算成本。
内容的提问来源于stack exchange,提问作者pm100
相关产品推荐
相关产品推荐

