SQL数据库算子执行模型分拉取式和推送式:拉取式由下游主动请求数据,适用于OLTP和复杂查询;推送式由上游主动发送数据,适合OLAP向量化与MPP场景;现代系统常混合使用二者。

SQL数据库的算子执行模型主要分为拉取式(Pull-based)和推送式(Push-based)两种,核心区别在于数据流动的控制权归属:拉取式由下游算子主动请求数据,推送式由上游算子主动发送数据。
拉取式执行模型的特点与典型实现
拉取式是传统关系数据库(如PostgreSQL、MySQL优化器)广泛采用的方式。执行时,根节点(如SELECT)发起next()调用,逐层向下触发子节点计算并返回一批元组(通常为1行或小批量),形成“迭代器树”结构。
- 每个算子实现统一接口(如Open()/Next()/Close()),封装内部状态,便于组合与复用
- 天然支持短路:例如LIMIT 10在获取足够行后可停止向下拉取,避免冗余计算
- 内存压力相对可控——数据按需生成,缓冲区小;但频繁函数调用和虚函数分发可能带来CPU开销
- 适合复杂嵌套查询和动态执行路径(如CASE、子查询依赖外层值)
推送式执行模型的特点与典型实现
推送式常见于现代列存分析引擎(如Doris、StarRocks、ClickHouse的部分执行阶段)及流处理系统。上游算子完成一批数据处理后,直接调用下游consume()接口推送数据块,控制流由数据生产者主导。
- 减少虚函数调用次数,利于CPU流水线和向量化执行——一次推送可处理千级行,提升吞吐
- 更易实现异步I/O和多线程并行:多个上游可并发推送至同一下游缓冲区
- 需要显式管理背压(backpressure),否则下游积压导致OOM;常配合通道容量限制或阻塞推送机制
- 对谓词下推、投影下推等优化更敏感——若下游无法及时消费,上游可能空转或需缓存中间结果
关键差异对比维度
二者并非互斥,实际系统常混合使用。例如Spark SQL物理计划中ShuffleExchange采用推送,而Filter/Project仍以拉取语义建模;TiDB的MPP模式中CN节点拉取,DN节点间通过RPC推送数据块。
- 控制流方向:拉取式是“自顶向下请求”,推送式是“自底向上供给”
- 数据粒度:拉取式倾向细粒度(单行/小批),推送式倾向粗粒度(Block/Chunk)
- 资源调度灵活性:拉取式易于按需暂停/恢复;推送式更适合固定pipeline编排与预分配内存
- 调试与可观测性:拉取式调用栈清晰,容易追踪执行路径;推送式需依赖事件日志或采样统计定位瓶颈
选型建议与趋势
OLTP场景多延续拉取式,保障低延迟与事务语义清晰;OLAP引擎则越来越多融合推送式,尤其在向量化、MPP、GPU加速等高性能路径中。新一代执行器(如DuckDB的VAAE、Presto的PipelinedQueryRunner)正通过统一抽象(如DataSink/DataSource接口)桥接两类模型,让优化器根据算子类型、数据规模、硬件特征自动选择最适数据流转方式。










