fdw_redis在PostgreSQL函数中未单查Redis,全量扫描问题求助
解决fdw_redis在PL/pgSQL函数中全量扫描Redis的问题
我之前也碰到过类似的FDW参数下推的坑,咱们来一步步拆解问题和解决方案:
问题根源
直接执行select "key", value from redis_db0_ch where "key"='Ch_152';时,PostgreSQL能识别到'Ch_152'是常量值,fdw_redis可以把这个过滤条件下推到Redis端,只发送ZRANGE "Ch_152" "0" "-1"请求,效率很高。
但在你的PL/pgSQL函数里,过滤条件是"key"='Ch_' || input_param——这是动态拼接的变量值。PL/pgSQL的静态查询(RETURN QUERY直接跟select语句)会在函数创建时就生成执行计划,此时input_param是未知变量,查询规划器没办法提前确定过滤条件的具体值,自然也就没法把条件下推给Redis,只能先把Redis里的所有记录全量拉到PostgreSQL本地,再做过滤。
解决方案:用动态SQL实现条件下推
把函数改成动态SQL的写法,让PostgreSQL在每次执行函数时,根据实际传入的参数值重新生成执行计划,这样fdw_redis就能识别到具体的过滤条件,把查询下推到Redis端。
修改后的函数代码如下:
CREATE OR REPLACE FUNCTION "SMSCEngine".f_get_redis_test(input_param integer) RETURNS TABLE(_key text, _value text) LANGUAGE plpgsql AS $function$ begin RETURN QUERY EXECUTE format( 'select "key", value from redis_db0_ch where "key" = %L', 'Ch_' || input_param ); end; $function$;
关键细节说明
EXECUTE会让PostgreSQL在运行时动态解析SQL语句,此时能拿到input_param的实际值,查询规划器可以生成带具体过滤条件的执行计划,fdw_redis就能正常下推请求到Redis。format函数的%L占位符会自动把拼接后的字符串转成带单引号的安全格式,避免SQL注入风险,这比直接字符串拼接更可靠。
验证效果
修改完成后,调用函数SELECT * FROM "SMSCEngine".f_get_redis_test(152);,再用redis-cli monitor观测,就能看到Redis只收到针对Ch_152的ZRANGE请求,不会再全量扫描所有记录了。
内容的提问来源于stack exchange,提问作者Churkin Anton
相关产品推荐
相关产品推荐

