首页
/ 3个维度掌握Doris执行计划:从原理到性能优化实战

3个维度掌握Doris执行计划:从原理到性能优化实战

2026-04-05 09:50:05作者:廉彬冶Miranda

问题引入:为什么慢查询总是找上你?

你是否遇到过这样的情况:明明昨天还跑得飞快的SQL,今天突然变得慢吞吞?或者同样的查询,换个时间段执行效率天差地别?在Apache Doris中,这些问题的背后往往藏着一个容易被忽视的关键角色——执行计划。这个由查询优化器生成的"操作指南",决定了数据如何被读取、处理和返回。就像烹饪同样的食材,不同的步骤顺序和火候控制会导致完全不同的结果,执行计划的优劣直接决定了查询性能的天花板。

核心概念:执行计划的"五脏六腑"

什么是执行计划?

执行计划是Doris查询优化器为SQL语句生成的详细执行方案,它像一张数据加工厂的流程图,规定了数据从存储到结果的完整处理路径。每个SQL语句在执行前都会经过优化器的"深思熟虑",最终生成由多个算子组成的执行链路。

执行计划的"快递分拣系统"模型

想象你是一家大型仓库的经理,需要处理来自全国各地的包裹(数据):

  • 扫描算子(SCAN) 就像仓库的拣货员,负责从货架(存储引擎)上取出包裹。不同的拣货策略(如OLAP_TABLE_SCAN、MYSQL_SCAN)适用于不同类型的货架。

  • 聚合算子(AGGREGATE) 类似打包员,将相同目的地的包裹(相同分组键的数据)合并装箱。Partial Aggregate就像区域中心的初步分拣,Final Aggregate则是总仓的最终打包。

  • 连接算子(JOIN) 好比包裹合并中心,将来自不同仓库的相关包裹(关联表数据)组合在一起。Hash Join像按收件人姓氏首字母快速匹配,Merge Join则适合已经按地址排序的包裹。

  • 交换算子(EXCHANGE) 相当于运输网络,负责将包裹在不同处理中心(节点)间转运。Hash Exchange按目的地邮编分发,Broadcast Exchange则将紧急包裹(小表数据)发送到所有处理中心。

执行计划算子关系示意图

执行计划的"交通地图"表示法

执行计划通常以表格形式展示,包含以下关键信息:

  • ID:算子的唯一编号,就像地图上的地标编号
  • OPERATOR:算子类型,相当于交通方式(公路、铁路、航空)
  • NAME:具体操作名称,如"哈希连接"、"流式聚合"
  • EST. ROWS:预估处理行数,类似预计运输货物量
  • EST. BYTES:预估数据量,相当于货物总体积
  • PROPERTIES:算子详细参数,包括过滤条件、连接键等

实践指南:执行计划的"驾驶技巧"

基础操作:如何"查看地图"

生成执行计划是分析查询性能的第一步,就像出发前查看导航地图:

-- 基本用法:生成执行计划
EXPLAIN SELECT user_id, COUNT(*) 
FROM orders 
WHERE order_date > '2023-01-01' 
GROUP BY user_id;

-- 进阶用法:指定使用Nereids优化器
EXPLAIN SELECT /*+ SET_VAR(enable_nereids_planner=true) */ 
user_id, SUM(amount) 
FROM orders 
JOIN users ON orders.user_id = users.id 
GROUP BY user_id;

参数调优:"调整导航偏好"

通过会话变量调整执行计划生成策略,就像设置导航的偏好(最快路线、最短距离等):

-- 启用SQL缓存
SET enable_sql_cache = true;

-- 调整哈希连接阈值(小表广播阈值)
SET hash_join_broadcast_threshold = 10485760; -- 10MB

-- 启用向量化执行
SET enable_vectorized_engine = true;

-- 设置并行度
SET parallel_fragment_exec_instance_num = 8;

异常处理:"道路救援"指南

当执行计划出现异常时,可采用以下方法诊断:

-- 1. 查看详细的执行统计信息
EXPLAIN ANALYZE SELECT ...;

-- 2. 强制刷新统计信息
ANALYZE TABLE orders WITH SYNC;

-- 3. 禁用特定优化规则
SET disable_rules = 'HashJoin';

-- 4. 使用HINT强制指定执行计划
SELECT /*+ USE_HASH_JOIN(orders) */ ...

案例分析:执行计划优化的"成功与失败"

成功案例:从全表扫描到精准定位

场景:某电商平台的商品分析查询,原始SQL如下:

SELECT category, SUM(sales) 
FROM products 
WHERE sale_date > '2023-01-01' 
GROUP BY category;

问题:执行计划显示全表扫描(PARTITIONS: []),扫描行数1000万+,执行时间20秒。

优化步骤

  1. 添加分区过滤条件:AND category = 'electronics'
  2. 创建sale_date的ZoneMap索引
  3. 启用向量化执行

优化后执行计划变化

  • SCAN算子的PARTITIONS变为['p202301', 'p202302']
  • 扫描行数从1000万+降至80万
  • 执行时间从20秒缩短至1.2秒

失败案例:错误的JOIN顺序导致性能恶化

场景:多表关联查询,原始SQL如下:

SELECT o.order_id, u.name, p.product_name
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id
WHERE o.order_date > '2023-01-01';

问题:优化器错误选择了先关联大表orders和users,导致中间结果集过大。

错误执行计划片段

| 0  | HASH_JOIN       |            | 100000   | ... |
| 1  |  HASH_JOIN      |            | 1000000  | ... |
| 2  |   SCAN          | ORDERS     | 5000000  | ... |  -- 大表先关联
| 3  |   SCAN          | USERS      | 1000000  | ... |
| 4  |  SCAN           | PRODUCTS   | 10000    | ... |  -- 小表后关联

解决方案:使用JOIN_ORDER hint强制小表优先关联:

SELECT /*+ JOIN_ORDER(p, u, o) */ 
o.order_id, u.name, p.product_name
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id
WHERE o.order_date > '2023-01-01';

进阶技巧:执行计划的"高级驾驶模式"

1. 算子下推优化

将过滤和聚合操作尽可能下推到存储层,减少数据传输量:

-- 推荐:过滤条件下推
SELECT category, SUM(sales)
FROM products
WHERE category = 'electronics'  -- 可下推到存储层的过滤条件
  AND sale_date > '2023-01-01'
GROUP BY category;

-- 不推荐:在应用层过滤
SELECT category, SUM(sales)
FROM (
  SELECT * FROM products 
  WHERE sale_date > '2023-01-01'  -- 仅部分过滤下推
) t
WHERE category = 'electronics'  -- 在计算层过滤
GROUP BY category;

2. 执行计划指纹比对

通过对比不同时期的执行计划指纹,快速定位性能退化原因:

-- 获取执行计划指纹
EXPLAIN FORMAT=FINGERPRINT 
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id;

-- 输出示例:
-- Fingerprint: 7a3f9d2e8c1b4a5d6e7f8a9b0c1d2e3f

将不同时期的指纹进行比对,若不一致则说明执行计划发生了变化,可能是统计信息更新或优化器版本变更导致。

工具局限性分析

Apache Doris执行计划分析工具虽然功能强大,但仍存在一些局限:首先,代价估算依赖统计信息的准确性,当数据分布发生显著变化而未及时更新统计信息时,可能导致次优计划;其次,对于复杂子查询和CTE的优化支持仍有提升空间;最后,某些特殊场景下(如极大数据倾斜),自动生成的执行计划可能需要人工干预。

扩展工具介绍

  1. Profile查看工具:位于tools/profile_viewer.py,可将查询Profile转换为可视化报告,帮助分析各算子的实际执行时间和资源消耗。

  2. Query Tuning工具:位于tools/qerror.py,自动检测SQL中的潜在性能问题,并提供优化建议,如索引缺失、数据倾斜等。

常见问题速查表

问题现象 可能原因 解决方案
执行计划中出现全表扫描 缺少分区键过滤或索引 添加分区过滤条件,创建合适的索引
JOIN操作耗时过长 连接顺序不当或缺少连接键索引 使用JOIN_ORDER hint,确保连接键有索引
聚合操作内存溢出 数据倾斜或部分聚合未启用 启用部分聚合,使用分桶聚合减少内存压力
执行计划与实际执行不符 统计信息过时 执行ANALYZE TABLE刷新统计信息
算子Est.Rows与实际偏差大 统计信息不准确 增加采样比例重新收集统计信息

通过掌握执行计划的分析方法,你已经获得了优化Doris查询性能的"透视眼"。记住,优秀的SQL性能不是偶然的,而是建立在对执行计划的深刻理解和持续优化之上。就像优秀的司机不仅会开车,更懂得读懂导航地图和路况一样,掌握执行计划分析技巧将让你在大数据查询的道路上畅行无阻。

登录后查看全文
热门项目推荐
相关项目推荐