Doris architecture

ANALYTICAL DATABASE / SOURCE READING / LESSON 18

Slow SQL and Query Profile tuning

Use slow SQL evidence, EXPLAIN, and Query Profile to move from symptoms to operator-level bottlenecks.

Reading
60 min
Track
Doris architecture
Source
Chinese source notes

The source notes for this track are currently maintained in Chinese.

预计阅读时间: 60 分钟 前置阅读: doc-01, doc-03, doc-04, doc-17 下一次阅读: doc-19(物化视图与查询加速)


1. 调优顺序: 不要从参数开始

慢 SQL 调优最容易犯的错误, 是看到慢就先改并发、内存、RuntimeFilter 等参数。专家调优应该按证据推进:

慢 SQL 识别
  → Schema 是否合理
    → EXPLAIN 静态计划是否合理
      → Profile 运行时瓶颈在哪里
        → 参数、索引、物化视图或 SQL 改写

Apache Doris 官方调优流程也是类似四步: 慢 SQL 识别、Schema 调优、计划调优、执行调优。

参考:


2. 先拿到慢 SQL

常见来源:

来源适合
fe.audit.log没有 Doris Manager 时的基础来源
audit_log 系统表SQL 化筛选慢查询
Doris Manager运维界面聚合
应用侧 trace/log关联业务请求

筛选维度:

query_time
scan_bytes / scan_rows
return_rows
user
database
workload_group
stmt

优先级不是只看耗时最长:

  • 频率高且总耗时高的 SQL 优先。
  • 影响核心看板或 API 的 SQL 优先。
  • 扫描量明显异常的 SQL 优先。
  • 偶发长尾要先判断是不是资源竞争、冷缓存或数据倾斜。

3. EXPLAIN 看静态计划

EXPLAIN 不运行 SQL, 它回答"计划是否看起来合理"。

EXPLAIN
SELECT service_name, count(*)
FROM event_log
WHERE event_time >= '2026-07-27 00:00:00'
  AND event_time <  '2026-07-28 00:00:00'
  AND tenant_id = 1001
GROUP BY service_name;

重点看:

位置你要问的问题
Scan Node是否命中正确 Partition 和 Tablet
predicates过滤条件是否下推
cardinality行数估计是否离谱
JoinBroadcast、Shuffle、Colocate 是否符合预期
Agg是否有本地预聚合
Exchange是否发生了昂贵的数据重分布
MV是否透明改写到物化视图

如果 EXPLAIN 已经显示扫描了大量无关分区, 不要急着看 Profile, 先回到建模和 SQL 条件。


4. Profile 看运行时真相

开启 Profile:

SET enable_profile = true;
SELECT ...;
SHOW PROFILELIST;
SHOW PROFILE WHERE query_id = '...';

Profile 的核心问题:

  1. 时间花在哪个 Fragment。
  2. 哪个 Operator 是瓶颈。
  3. Scan 是慢在 I/O、解压、过滤还是远端读取。
  4. Join 是慢在 Build、Probe、Shuffle 还是数据倾斜。
  5. Agg/Sort 是否内存不足或 Spill。
  6. Exchange 是否网络拥塞或下游反压。

一个简化阅读顺序:

Query Total Time
  → Fragment Instance Time
    → Operator Time
      → Rows / Bytes / Blocks
        → Wait Time / Peak Memory / Spill / Filter Rows

5. Scan 慢怎么判断

Scan 是 OLAP 慢查询最常见瓶颈。先拆成四类:

5.1 扫描范围过大

症状:

  • Partition 裁剪很少。
  • Tablet 数非常多。
  • scan_rows 远大于返回行数。

处理:

  • SQL 加上分区列条件。
  • 调整 Partition 粒度。
  • 调整 Sort Key。
  • 为高频等值列补 Bloom Filter 或 Inverted Index。
  • 把重复查询模式做成物化视图。

5.2 数据分布倾斜

症状:

  • 某些 Fragment Instance 时间明显长。
  • 某些 Tablet 大小明显偏大。
  • Hash Bucket 的 Key 有热点。

处理:

SHOW TABLETS FROM table_name;
  • 换更均匀的 Bucket Key。
  • 对明细日志使用 Random Bucketing。
  • 对热点租户拆表或拆更细分区。

5.3 I/O 慢

症状:

  • Scan 时间高, CPU 不高。
  • 外表查询远慢于内表。
  • Data Cache 命中率低。

处理:

  • 内表: 检查磁盘、Compaction、Segment 数和 Page Cache。
  • 湖仓: 开启 Data Cache, 预热热点数据, 控制小文件。

5.4 过滤没下推

症状:

  • Profile 中扫描行很多, 上层 Filter 才过滤。
  • 函数包裹列导致谓词无法下推。

反例:

WHERE date(event_time) = '2026-07-27'

更好:

WHERE event_time >= '2026-07-27 00:00:00'
  AND event_time <  '2026-07-28 00:00:00'

6. Join 慢怎么判断

Join 慢通常来自四件事:

问题现象方向
Join 顺序不合理大表先 Join 大表统计信息、Leading Hint
Shuffle 太重Exchange 时间高Colocate、Broadcast 小表
Build 侧太大Hash Table 内存高过滤前移、聚合前移
数据倾斜某个 Instance 远慢于其他拆热点 Key、改 Join 策略

检查思路:

EXPLAIN SELECT ...

看每个 Join:

  • Build Side 是不是小表。
  • RuntimeFilter 是否生成并下推。
  • 是否出现多层 Exchange。
  • 是否能用 Colocate Group 避免 Shuffle。

7. Agg / Sort / TopN 慢怎么判断

聚合慢

原因:

  • Group By 基数太高。
  • 扫描数据过大。
  • 本地预聚合效果差。
  • 内存不足导致 Spill。

处理:

  • 使用 Aggregate Key 或物化视图预聚合。
  • 用 Bitmap/HLL 处理去重。
  • 提前过滤。
  • 检查 Workload Group 内存。

Sort / TopN 慢

ORDER BY ... LIMIT n 可以触发 TopN 优化, 但不是所有场景都有效。

处理思路:

  • 确认 LIMIT 是否足够小。
  • 排序列是否能被索引或排序键帮助。
  • Profile 中看 TopN 过滤效果。
  • 大分页不要用 OFFSET 深翻页, 改为游标条件。

参考:


8. 统计信息与 CBO

Nereids 的 CBO 依赖统计信息。统计不准时, 优化器可能低估大表、误判 Join 顺序、选错 Broadcast 或 Shuffle。

常见动作:

ANALYZE TABLE table_name;
SHOW COLUMN STATS table_name;

调优判断:

  • 表数据变化很大后重新收集统计。
  • 大表 Join 前确认 Join Key 统计存在。
  • 过滤列的 NDV 估计明显错误时, 计划可能不稳定。

9. 参数调优应该放在最后

参数是最后一公里, 不是第一选择。

参数方向先确认
并行度是否真的 CPU 不满且 Scan 并行不足
RuntimeFilter 等待RF 是否有过滤收益
Spill是否允许用磁盘换稳定性
Workload Group是否是多租户资源竞争
SQL Block / Policy是否需要保护集群稳定

专家调优报告应该包含:

1. 慢 SQL 和业务影响
2. 当前表结构与数据量
3. EXPLAIN 计划摘要
4. Profile 瓶颈证据
5. 变更方案和风险
6. 验证 SQL 与前后对比
7. 是否需要回滚

一句话总结:

EXPLAIN 解释"系统准备怎么做", Profile 解释"系统实际怎么慢"; Doris 专家要能把二者连回表设计、执行引擎和资源治理。