Optimizer 优化器是查询引擎的“大脑”,通过规则重写(RBO)和基于成本的优化(CBO),从众多执行计划中挑选最优方案,交给执行引擎。本文基于 StarRocks-3.4.0 源码,结合案例深入剖析优化器的规则重写机制,揭示如何通过减少无效数据计算提升查询性能。
Optimizer的核心功能
Optimizer优化SQL查询执行计划,主要通过以下两种方式:
在《极致性能背后的黑科技?这个世上没有“银弹”!(二)》一文中,从数据量这一角度分析StarRocks是如何让查询速度更快,简而言之,就是"越少无效的数据参与计算,越快的速度"。而本文要介绍的部分规则重写,其实也是这一思想的体现,目的就是让更个环节减少无效的数据参与计算。
Optimizer规则重写的实现
在Optimizer.java中,logicalRuleRewrite 是 StarRocks 优化器实现规则重写的核心方法,通过一系列逻辑优化规则对 Logical Plan 进行重写和优化,传进去的 tree 正是上一阶段构建好的 Logical Plan。

RuleSetType 枚举定义了一系列优化规则集,用于在 logicalRuleRewrite 方法中对查询计划进行重写和优化,旨在减少查询的计算开销、IO 开销和数据处理量,从而提高查询性能。
public enum RuleSetType { LOGICAL_TRANSFORMATION, // 逻辑计划转换 PHYSICAL_IMPLEMENTATION, // 物理计划实现 MERGE_LIMIT, // 合并 LIMIT 操作 PRUNE_COLUMNS, // 列裁剪 PUSH_DOWN_PREDICATE, // 谓词下推 SUBQUERY_REWRITE_COMMON, // 子查询重写 ... VECTOR_REWRITE // 向量化重写}案例分析
以下面2张表作为例子,建表语句及字段如下:
CREATE TABLE IF NOT EXISTS customers ( id BIGINT NOT NULL, name VARCHAR(100), age INT, email VARCHAR(100)) ENGINE = olapDUPLICATE KEY (id)DISTRIBUTED BY HASH(id)PROPERTIES ( "replication_num" = "3"); CREATE TABLE IF NOT EXISTS orders ( order_id BIGINT, customer_id INT, order_date DATE, amount DECIMAL(10,2)) ENGINE = olap DUPLICATE KEY(order_id)DISTRIBUTED BY HASH(order_id)PROPERTIES ( "replication_num" = "3");常见的重写规则
一. 谓词下推(PUSH_DOWN_PREDICATE)
谓词下推的核心思想是尽早过滤数据,避免将不必要的数据加载到计算层。通过将过滤条件下推到存储层(如文件扫描),可以在数据读取时直接跳过不符合条件的数据,减少 I/O 和计算开销。
SELECT o.order_id, o.amount, c.nameFROM orders oJOIN customers c ON o.customer_id = c.customer_idWHERE o.order_date = '2025-08-01' AND c.country = 'China';优化前的逻辑计划树
过滤条件 o.order_date = '2025-08-01' 和 c.country = 'China' 在 Join 后应用,导致 orders 和 customers 表扫描了全表数据。

优化后最终的执行计划
通过Explain命令查看,将 o.order_date = '2025-08-01' 下推到 orders 表的扫描节点,c.country = 'China' 下推到 customers 表的扫描节点。扫描时只读取满足条件的行,减少了 Join 操作的输入数据量。

二. 列裁剪 (PRUNE_COLUMNS)
列裁剪移除查询计划中不需要的列,减少数据传输和计算开销。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01';优化前的逻辑计划树
扫描 orders 表,读取所有列:order_id, customer_id, order_date, amount

优化后最终的执行计划
通过Explain命令查看,只扫描查询所需的列,最终只输出列:order_id, customer_id。减少了读取的数据量,对宽表(列数多)或数据量大的场景,列裁剪能显著减少 IO 和计算成本。这也是在SQL中尽量避免使用 "SELECT * "的原因。

三. LIMIT下推合并 (MERGE_LIMIT)
Limit 下推是指将查询中的 LIMIT 子句尽可能“下推”到 SCAN 阶段,从而减少后续操作需要处理的数据量;Limit Merge 是一种优化技术,用于合并多个 LIMIT 子句,避免重复计算。当一个查询中包含多个 LIMIT 子句时,StarRocks 会尝试将它们合并为一个更高效的 LIMIT。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01' LIMIT 1;优化前的逻辑计划树
在没有 LIMIT 下推的情况下,查询会先扫描所有符合 order_date = '2025-08-01' 条件的数据,然后在最后阶段应用 LIMIT 1。

SCAN 节点没有 LIMIT 限制

优化后最终的执行计划
通过 LIMIT 下推,SCAN 在扫描数据时直接限制 LIMIT 1,当读取满足 order_date = '2025-08-01' 条件的一条数据后,就停止读取,从而减少 IO 和计算开销。

除上述规则外,StarRocks 还支持以下优化:
.......
在下一篇文章《StarRocks 查询探秘(五):Optimizer优化器之基于成本优化》中,将以一个线上外表查询计划构建频繁超时为例,深入分析 CBO的原理,敬请期待!
Optimizer 优化器是查询引擎的“大脑”,通过规则重写(RBO)和基于成本的优化(CBO),从众多执行计划中挑选最优方案,交给执行引擎。本文基于 StarRocks-3.4.0 源码,结合案例深入剖析优化器的规则重写机制,揭示如何通过减少无效数据计算提升查询性能。
Optimizer的核心功能
Optimizer优化SQL查询执行计划,主要通过以下两种方式:
在《极致性能背后的黑科技?这个世上没有“银弹”!(二)》一文中,从数据量这一角度分析StarRocks是如何让查询速度更快,简而言之,就是"越少无效的数据参与计算,越快的速度"。而本文要介绍的部分规则重写,其实也是这一思想的体现,目的就是让更个环节减少无效的数据参与计算。
Optimizer规则重写的实现
在Optimizer.java中,logicalRuleRewrite 是 StarRocks 优化器实现规则重写的核心方法,通过一系列逻辑优化规则对 Logical Plan 进行重写和优化,传进去的 tree 正是上一阶段构建好的 Logical Plan。

RuleSetType 枚举定义了一系列优化规则集,用于在 logicalRuleRewrite 方法中对查询计划进行重写和优化,旨在减少查询的计算开销、IO 开销和数据处理量,从而提高查询性能。
public enum RuleSetType { LOGICAL_TRANSFORMATION, // 逻辑计划转换 PHYSICAL_IMPLEMENTATION, // 物理计划实现 MERGE_LIMIT, // 合并 LIMIT 操作 PRUNE_COLUMNS, // 列裁剪 PUSH_DOWN_PREDICATE, // 谓词下推 SUBQUERY_REWRITE_COMMON, // 子查询重写 ... VECTOR_REWRITE // 向量化重写}案例分析
以下面2张表作为例子,建表语句及字段如下:
CREATE TABLE IF NOT EXISTS customers ( id BIGINT NOT NULL, name VARCHAR(100), age INT, email VARCHAR(100)) ENGINE = olapDUPLICATE KEY (id)DISTRIBUTED BY HASH(id)PROPERTIES ( "replication_num" = "3"); CREATE TABLE IF NOT EXISTS orders ( order_id BIGINT, customer_id INT, order_date DATE, amount DECIMAL(10,2)) ENGINE = olap DUPLICATE KEY(order_id)DISTRIBUTED BY HASH(order_id)PROPERTIES ( "replication_num" = "3");常见的重写规则
一. 谓词下推(PUSH_DOWN_PREDICATE)
谓词下推的核心思想是尽早过滤数据,避免将不必要的数据加载到计算层。通过将过滤条件下推到存储层(如文件扫描),可以在数据读取时直接跳过不符合条件的数据,减少 I/O 和计算开销。
SELECT o.order_id, o.amount, c.nameFROM orders oJOIN customers c ON o.customer_id = c.customer_idWHERE o.order_date = '2025-08-01' AND c.country = 'China';优化前的逻辑计划树
过滤条件 o.order_date = '2025-08-01' 和 c.country = 'China' 在 Join 后应用,导致 orders 和 customers 表扫描了全表数据。

优化后最终的执行计划
通过Explain命令查看,将 o.order_date = '2025-08-01' 下推到 orders 表的扫描节点,c.country = 'China' 下推到 customers 表的扫描节点。扫描时只读取满足条件的行,减少了 Join 操作的输入数据量。

二. 列裁剪 (PRUNE_COLUMNS)
列裁剪移除查询计划中不需要的列,减少数据传输和计算开销。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01';优化前的逻辑计划树
扫描 orders 表,读取所有列:order_id, customer_id, order_date, amount

优化后最终的执行计划
通过Explain命令查看,只扫描查询所需的列,最终只输出列:order_id, customer_id。减少了读取的数据量,对宽表(列数多)或数据量大的场景,列裁剪能显著减少 IO 和计算成本。这也是在SQL中尽量避免使用 "SELECT * "的原因。

三. LIMIT下推合并 (MERGE_LIMIT)
Limit 下推是指将查询中的 LIMIT 子句尽可能“下推”到 SCAN 阶段,从而减少后续操作需要处理的数据量;Limit Merge 是一种优化技术,用于合并多个 LIMIT 子句,避免重复计算。当一个查询中包含多个 LIMIT 子句时,StarRocks 会尝试将它们合并为一个更高效的 LIMIT。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01' LIMIT 1;优化前的逻辑计划树
在没有 LIMIT 下推的情况下,查询会先扫描所有符合 order_date = '2025-08-01' 条件的数据,然后在最后阶段应用 LIMIT 1。

SCAN 节点没有 LIMIT 限制

优化后最终的执行计划
通过 LIMIT 下推,SCAN 在扫描数据时直接限制 LIMIT 1,当读取满足 order_date = '2025-08-01' 条件的一条数据后,就停止读取,从而减少 IO 和计算开销。

除上述规则外,StarRocks 还支持以下优化:
.......
在下一篇文章《StarRocks 查询探秘(五):Optimizer优化器之基于成本优化》中,将以一个线上外表查询计划构建频繁超时为例,深入分析 CBO的原理,敬请期待!
Optimizer 优化器是查询引擎的“大脑”,通过规则重写(RBO)和基于成本的优化(CBO),从众多执行计划中挑选最优方案,交给执行引擎。本文基于 StarRocks-3.4.0 源码,结合案例深入剖析优化器的规则重写机制,揭示如何通过减少无效数据计算提升查询性能。
Optimizer的核心功能
Optimizer优化SQL查询执行计划,主要通过以下两种方式:
在《极致性能背后的黑科技?这个世上没有“银弹”!(二)》一文中,从数据量这一角度分析StarRocks是如何让查询速度更快,简而言之,就是"越少无效的数据参与计算,越快的速度"。而本文要介绍的部分规则重写,其实也是这一思想的体现,目的就是让更个环节减少无效的数据参与计算。
Optimizer规则重写的实现
在Optimizer.java中,logicalRuleRewrite 是 StarRocks 优化器实现规则重写的核心方法,通过一系列逻辑优化规则对 Logical Plan 进行重写和优化,传进去的 tree 正是上一阶段构建好的 Logical Plan。

RuleSetType 枚举定义了一系列优化规则集,用于在 logicalRuleRewrite 方法中对查询计划进行重写和优化,旨在减少查询的计算开销、IO 开销和数据处理量,从而提高查询性能。
public enum RuleSetType { LOGICAL_TRANSFORMATION, // 逻辑计划转换 PHYSICAL_IMPLEMENTATION, // 物理计划实现 MERGE_LIMIT, // 合并 LIMIT 操作 PRUNE_COLUMNS, // 列裁剪 PUSH_DOWN_PREDICATE, // 谓词下推 SUBQUERY_REWRITE_COMMON, // 子查询重写 ... VECTOR_REWRITE // 向量化重写}案例分析
以下面2张表作为例子,建表语句及字段如下:
CREATE TABLE IF NOT EXISTS customers ( id BIGINT NOT NULL, name VARCHAR(100), age INT, email VARCHAR(100)) ENGINE = olapDUPLICATE KEY (id)DISTRIBUTED BY HASH(id)PROPERTIES ( "replication_num" = "3"); CREATE TABLE IF NOT EXISTS orders ( order_id BIGINT, customer_id INT, order_date DATE, amount DECIMAL(10,2)) ENGINE = olap DUPLICATE KEY(order_id)DISTRIBUTED BY HASH(order_id)PROPERTIES ( "replication_num" = "3");常见的重写规则
一. 谓词下推(PUSH_DOWN_PREDICATE)
谓词下推的核心思想是尽早过滤数据,避免将不必要的数据加载到计算层。通过将过滤条件下推到存储层(如文件扫描),可以在数据读取时直接跳过不符合条件的数据,减少 I/O 和计算开销。
SELECT o.order_id, o.amount, c.nameFROM orders oJOIN customers c ON o.customer_id = c.customer_idWHERE o.order_date = '2025-08-01' AND c.country = 'China';优化前的逻辑计划树
过滤条件 o.order_date = '2025-08-01' 和 c.country = 'China' 在 Join 后应用,导致 orders 和 customers 表扫描了全表数据。

优化后最终的执行计划
通过Explain命令查看,将 o.order_date = '2025-08-01' 下推到 orders 表的扫描节点,c.country = 'China' 下推到 customers 表的扫描节点。扫描时只读取满足条件的行,减少了 Join 操作的输入数据量。

二. 列裁剪 (PRUNE_COLUMNS)
列裁剪移除查询计划中不需要的列,减少数据传输和计算开销。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01';优化前的逻辑计划树
扫描 orders 表,读取所有列:order_id, customer_id, order_date, amount

优化后最终的执行计划
通过Explain命令查看,只扫描查询所需的列,最终只输出列:order_id, customer_id。减少了读取的数据量,对宽表(列数多)或数据量大的场景,列裁剪能显著减少 IO 和计算成本。这也是在SQL中尽量避免使用 "SELECT * "的原因。

三. LIMIT下推合并 (MERGE_LIMIT)
Limit 下推是指将查询中的 LIMIT 子句尽可能“下推”到 SCAN 阶段,从而减少后续操作需要处理的数据量;Limit Merge 是一种优化技术,用于合并多个 LIMIT 子句,避免重复计算。当一个查询中包含多个 LIMIT 子句时,StarRocks 会尝试将它们合并为一个更高效的 LIMIT。
SELECT order_id, customer_idFROM ordersWHERE order_date = '2025-08-01' LIMIT 1;优化前的逻辑计划树
在没有 LIMIT 下推的情况下,查询会先扫描所有符合 order_date = '2025-08-01' 条件的数据,然后在最后阶段应用 LIMIT 1。

SCAN 节点没有 LIMIT 限制

优化后最终的执行计划
通过 LIMIT 下推,SCAN 在扫描数据时直接限制 LIMIT 1,当读取满足 order_date = '2025-08-01' 条件的一条数据后,就停止读取,从而减少 IO 和计算开销。

除上述规则外,StarRocks 还支持以下优化:
.......
在下一篇文章《StarRocks 查询探秘(五):Optimizer优化器之基于成本优化》中,将以一个线上外表查询计划构建频繁超时为例,深入分析 CBO的原理,敬请期待!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。