暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

postgres_fdw无法下推where条件原理探究

原创 NickYoung 2024-09-13
333

前言

今天在pgfans问答社区看到一个问题,使用postgres_fdw创建的外表进行查询时where没推到remote端执行。
如图:
可以看到当where条件对空间类型做函数计算匹配时,where条件没有推至remote,而是查询了remote全量数据,where条件作为local filter来过滤数据。
image.png
这是为什么呢?

原理分析

postgres_fdw是否下推expr至remote,主要取决于is_foreign_expr函数的判断。
函数中返回false的位置,就是不下推至remote的几种场景。

主要是:
1、foreign_expr_walker函数返回false;
2、表达式的有效排序规则不是由foreign var产生的;
3、包含任何可变函数的表达式不能被发送,因为它的结果不稳定。

/* * Returns true if given expr is safe to evaluate on the foreign server. */ bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr) { foreign_glob_cxt glob_cxt; foreign_loc_cxt loc_cxt; PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private); /* * Check that the expression consists of nodes that are safe to execute * remotely. */ glob_cxt.root = root; glob_cxt.foreignrel = baserel; /* * For an upper relation, use relids from its underneath scan relation, * because the upperrel's own relids currently aren't set to anything * meaningful by the core code. For other relation, use their own relids. */ if (IS_UPPER_REL(baserel)) glob_cxt.relids = fpinfo->outerrel->relids; else glob_cxt.relids = baserel->relids; loc_cxt.collation = InvalidOid; loc_cxt.state = FDW_COLLATE_NONE; if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt, NULL)) return false; /* * If the expression has a valid collation that does not arise from a * foreign var, the expression can not be sent over. */ if (loc_cxt.state == FDW_COLLATE_UNSAFE) return false; /* * An expression which includes any mutable functions can't be sent over * because its result is not stable. For example, sending now() remote * side could cause confusion from clock offsets. Future versions might * be able to make this choice with more granularity. (We check this last * because it requires a lot of expensive catalog lookups.) */ if (contain_mutable_functions((Node *) expr)) return false; /* OK to evaluate on the remote server */ return true; }

给对应函数设置断点,debug追踪下我们这个case。
进入is_foreign_expr函数,我们当前的expr的nodetag为T_FuncExpr。
image.png

进入foreign_expr_walker函数,对应到case:T_FuncExpr,调用is_shippable函数。
image.png

进入is_shippable函数,判断fpinfo->shippable_extensions == NIL所以 return false
image.png

classifyConditions函数中:因此我们的is_foreign_expr函数也返回false了,那么我们expr就被append到local_conds而非remote_conds。
image.png

那么这样就导致我们的expr没有被下推至remote,核心问题在于为什么fpinfo->shippable_extensions == NIL,这个变量是什么?

apply_server_options函数中可以找到答案,fpinfo->shippable_extensions取的是我们创建的server的option中的extensions配置项,如果没指定则为NULL。
我们的where条件中ST_DWithin这个函数为postgis插件的函数,因此看起来将server options extensions设置postgis就可以下推至remote了?

/* * Parse options from foreign server and apply them to fpinfo. * * New options might also require tweaking merge_fdw_options(). */ static void apply_server_options(PgFdwRelationInfo *fpinfo) { ListCell *lc; foreach(lc, fpinfo->server->options) { DefElem *def = (DefElem *) lfirst(lc); if (strcmp(def->defname, "use_remote_estimate") == 0) fpinfo->use_remote_estimate = defGetBoolean(def); else if (strcmp(def->defname, "fdw_startup_cost") == 0) (void) parse_real(defGetString(def), &fpinfo->fdw_startup_cost, 0, NULL); else if (strcmp(def->defname, "fdw_tuple_cost") == 0) (void) parse_real(defGetString(def), &fpinfo->fdw_tuple_cost, 0, NULL); else if (strcmp(def->defname, "extensions") == 0) fpinfo->shippable_extensions = ExtractExtensionList(defGetString(def), false); else if (strcmp(def->defname, "fetch_size") == 0) (void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL); else if (strcmp(def->defname, "async_capable") == 0) fpinfo->async_capable = defGetBoolean(def); } }

解决方案

执行alter server testserver options (extensions ‘postgis’);
发现where条件可以下推至remote去执行。
image.png

小结

对于postgres_fdw是否会将where条件下推至remote执行有以下规则:

where条件中如果使用到了插件对应的function、operator、type等,那么首先在server的option里要配置这个extension。

满足这几种条件就不会下推至remote:
1、foreign_expr_walker函数返回false;
2、表达式的有效排序规则不是由foreign var产生的;
3、包含任何可变函数的表达式不能被发送,因为它的结果不稳定。

最后修改时间:2024-09-13 10:37:51
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论