PostgreSQL 查询执行器:从火山模型到向量化执行的演进与工程实践

数据库内核的执行层是整个系统的"最后一公里"——查询优化器生成一份精确的施工图纸,而执行器负责按图把结果造出来。过去三十年里,PostgreSQL 一直使用经典的火山模型(Volcano Model)驱动执行流;而在 OLAP 和大规模数据分析场景下,向量化执行(Vectorized Execution)以数量级的性能优势逐渐成了新的事实标准。

这篇文章将从 PostgreSQL 的源码出发,深度剖析两种执行模型的实现机制、性能差异,并展示在真实业务中如何选择和调优。

一、火山模型:迭代器驱动的优雅与代价

1.1 架构原理

火山模型由 Goetz Graefe 在 1993 年提出,核心思想是:每个算子(Operator)实现一组统一的接口(open()、next()、close()),算子之间像流水线一样串联。上游算子每次调用 next() 向下游要一条 tuple(行),源头算子(如 SeqScan)从磁盘或 buffer pool 中取一条数据,逐级向上传递。

PostgreSQL 的执行框架在 src/backend/executor/ 目录下,核心数据结构是 PlanState:

// src/include/nodes/execnodes.h
typedef struct PlanState {
    NodeTag           type;
    Plan             *plan;          // 对应的执行计划节点
    EState           *state;         // 全局执行状态
    TupleTableSlot   *ps_ResultTupleSlot;  // 输出槽
    ProjectionInfo   *ps_ProjInfo;    // 投影信息

    // 左右子树
    struct PlanState *lefttree;
    struct PlanState *righttree;

    // 执行方法(每个算子有自己的 ExecProcNode 实现)
    ExecProcNodeMtd   ExecProcNode;   // 核心:获取下一条 tuple
    ExecProcNodeMtd   ExecProcNodeReal;
    ExprStateQual     *qual;          // 过滤条件
} PlanState;

以 SeqScan 为例,ExecSeqScan 的工作就是每次被调用时,用 table_scan_getnextslot 从存储层获得一条 tuple,填充到 slot 中后返回。

1.2 一个简单的过滤 投影执行流程

// SeqScanState 的 next()
static TupleTableSlot *
ExecSeqScan(PlanState *pstate)
{
    ScanState *node = castNode(ScanState, pstate);
    TupleTableSlot *slot = node-                        
                    
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部