PostgreSQL 13.8 子查询优化实战:手把手教你读懂 `pull_up_sublinks` 源码
PostgreSQL 13.8 子查询优化实战手把手教你读懂pull_up_sublinks源码数据库查询优化器是数据库系统的核心组件之一它负责将用户提交的SQL语句转换为高效的执行计划。在PostgreSQL中子查询优化是查询优化的重要环节而pull_up_sublinks则是处理WHERE子句中子查询子链接的关键函数。本文将带您深入PostgreSQL 13.8源码从实战角度解析这一优化过程。1. 环境准备与源码定位要深入理解pull_up_sublinks的工作原理首先需要搭建一个适合的调试环境。以下是推荐的开发环境配置操作系统Linux推荐Ubuntu 20.04 LTSPostgreSQL版本13.8源码调试工具GDB 10.1编译选项./configure --enable-debug关键源码文件位于src/backend/optimizer/prep/prepjointree.c中。我们可以通过以下步骤快速定位到目标函数# 在PostgreSQL源码目录中 grep -rn pull_up_sublinks src/backend/在GDB中设置断点的命令示例break pull_up_sublinks_jointree_recurse break pull_up_sublinks_qual_recurse2. 子链接优化的核心数据结构理解PostgreSQL中的关键数据结构是分析优化器行为的基础。以下是pull_up_sublinks处理过程中涉及的主要数据结构数据结构描述关键字段PlannerInfo查询规划上下文parse查询树、simple_rel_array基本关系数组Query查询树表示jointreeFROM/WHERE子句、targetListSELECT列表FromExprFROM子句节点fromlistFROM列表、qualsWHERE条件JoinExprJOIN表达式jointype连接类型、larg/rarg左右参数RangeTblRef范围表引用rtindex范围表索引SubLink子链接表达式subLinkType子链接类型、testexpr测试表达式这些数据结构共同构成了查询优化器处理子链接的基础框架。特别值得注意的是SubLink类型它定义了PostgreSQL支持的子链接类型typedef enum SubLinkType { EXISTS_SUBLINK, ALL_SUBLINK, ANY_SUBLINK, ROWCOMPARE_SUBLINK, EXPR_SUBLINK, MULTIEXPR_SUBLINK, ARRAY_SUBLINK, CTE_SUBLINK } SubLinkType;3. 子链接上拉的递归处理流程pull_up_sublinks的核心是一个递归处理过程主要包含两个关键函数pull_up_sublinks_jointree_recurse处理FROM子句中的连接树pull_up_sublinks_qual_recurse处理WHERE子句中的条件表达式以下是pull_up_sublinks_jointree_recurse的简化处理逻辑static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids) { if (jtnode NULL) { *relids NULL; } else if (IsA(jtnode, RangeTblRef)) { // 处理基础表引用 int varno ((RangeTblRef *) jtnode)-rtindex; *relids bms_make_singleton(varno); } else if (IsA(jtnode, FromExpr)) { // 处理FROM表达式 FromExpr *f (FromExpr *) jtnode; // 递归处理FROM列表 foreach(l, f-fromlist) { newchild pull_up_sublinks_jointree_recurse(root, lfirst(l), childrelids); newfromlist lappend(newfromlist, newchild); } // 处理WHERE条件 newf-quals pull_up_sublinks_qual_recurse(root, f-quals, jtlink, frelids, NULL, NULL); } else if (IsA(jtnode, JoinExpr)) { // 处理JOIN表达式 JoinExpr *j (JoinExpr *) jtnode; // 递归处理左右子树 j-larg pull_up_sublinks_jointree_recurse(root, j-larg, leftrelids); j-rarg pull_up_sublinks_jointree_recurse(root, j-rarg, rightrelids); // 根据连接类型处理连接条件 switch (j-jointype) { case JOIN_INNER: j-quals pull_up_sublinks_qual_recurse(root, j-quals, jtlink, bms_union(leftrelids, rightrelids), NULL, NULL); break; case JOIN_LEFT: j-quals pull_up_sublinks_qual_recurse(root, j-quals, j-rarg, rightrelids, NULL, NULL); break; // 其他连接类型处理... } } return jtnode; }4. 不同类型子链接的转换策略PostgreSQL对不同类型的子链接采用不同的转换策略主要通过pull_up_sublinks_qual_recurse函数实现4.1 ANY子链接的转换ANY子链接包括IN、SOME等会被转换为半连接SEMI JOIN。转换过程由convert_ANY_sublink_to_join函数完成JoinExpr * convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, Relids available_rels) { // 检查子查询是否引用外层变量 if (contain_vars_of_level((Node *) subselect, 1)) return NULL; // 创建新的RangeTblEntry nsitem addRangeTableEntryForSubquery(pstate, subselect, makeAlias(ANY_subquery, NIL), false, false); // 构建JoinExpr result makeNode(JoinExpr); result-jointype JOIN_SEMI; result-rarg (Node *) rtr; // 子查询作为右参数 result-quals convert_testexpr(root, sublink-testexpr, subquery_vars); return result; }4.2 EXISTS子链接的转换EXISTS子链接同样会被转换为半连接而NOT EXISTS则会被转换为反连接ANTI JOIN。这是通过convert_EXISTS_sublink_to_join函数实现的JoinExpr * convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, bool under_not, Relids available_rels) { // 简化EXISTS查询 if (!simplify_EXISTS_query(root, subselect)) return NULL; // 提取WHERE条件 whereClause subselect-jointree-quals; // 构建JoinExpr result makeNode(JoinExpr); result-jointype under_not ? JOIN_ANTI : JOIN_SEMI; // 直接使用子查询中的FROM列表 if (list_length(subselect-jointree-fromlist) 1) result-rarg (Node *) linitial(subselect-jointree-fromlist); else result-rarg (Node *) subselect-jointree; result-quals whereClause; return result; }5. 实战调试技巧与案例分析要真正理解子链接优化的过程最好的方法是通过实际案例进行调试分析。以下是一个典型的调试流程准备测试SQLEXPLAIN SELECT * FROM orders o WHERE EXISTS (SELECT 1 FROM customers c WHERE c.id o.customer_id AND c.status active);设置断点break pull_up_sublinks break pull_up_sublinks_jointree_recurse break convert_EXISTS_sublink_to_join关键调试观察点subselect-jointree-quals的变化available_rels的传递过程生成的JoinExpr结构在调试过程中可以重点关注以下变量root-parse-jointree查询的FROM/WHERE结构sublink-subLinkType子链接类型j-jointype生成的连接类型通过实际跟踪这些数据结构的变换过程可以深入理解PostgreSQL如何将子查询转换为更高效的连接操作。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2626274.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!