Doris优化---持续更新

131 阅读7分钟

1.慢查询的定位、优化、验证结果

(1) 慢日志问题排查

Doris 提供慢查询审计日志EXPLAIN/PROFILE 工具链,实现从 “宏观耗时统计” 到 “微观执行细节” 的全链路剖析。

<1> 慢查询日志:宏观定位耗时 SQL

Doris 默认记录执行时间超过阈值(可通过query_timeout配置,默认 300 秒)的 SQL 至慢查询日志,日志中包含 SQL 语句、执行时长、扫描行数、返回行数、用户信息、客户端 IP 等关键信息。通过分析日志可快速筛选出高频慢查询、大扫描量 SQL 等问题语句

例如 “单条 SQL 扫描超 1 亿行却仅返回 10 行” 的低效查询,可初步判断为缺少索引或分区剪裁失效。

<2> EXPLAIN:解析查询计划

针对慢查询,使用EXPLAIN语句可查看其执行计划,包括数据扫描方式(全表扫描 / 索引扫描)、分区剪裁情况、Join 算法选择、聚合位置、数据 Shuffle 策略等。例如:

  • 若计划中在执行计划中,OlapScanNode 节点的 partitions字段能够看到当前查询扫描的分区;

<3> PROFILE:追踪执行细节

对于复杂慢查询,PROFILE工具可提供更细粒度的执行 metrics,包括各阶段耗时(如 Scan、Join、Aggregate、Sort)、CPU / 内存占用、I/O 吞吐量、节点执行状态等。例如:

  • 若 “Scan” 阶段耗时占比超 80%,可能是分区剪裁失效、缺少索引或数据分片不合理;
  • 若 “Shuffle” 阶段耗时过长,需检查分桶键设计是否导致数据倾斜,或调整 Shuffle 顺序。

(2) Schema的优化手段

<1> 分区与分桶设计

  • 分区设计:通过分区键(如时间、地域)将大表拆分为小分区,查询时可通过分区剪裁过滤无关数据,减少扫描范围。例如日志表按 “天” 分区,查询 “近 7 天日志” 仅扫描 7 个分区,而非全表。需注意分区粒度:粒度过细(如按小时分区)会导致分区数量过多,增加元数据管理开销;粒度过粗(如按年分区)则无法发挥剪裁价值,建议根据数据增长速度与查询频率选择(如日增 100GB 数据选 “天分区”,日增 10GB 选 “周分区”)。
  • 分桶设计:通过分桶键(如用户 ID、订单 ID)将分区内数据均匀分散到多个 Tablet,实现并行扫描与计算。分桶键需选择基数高、分布均匀的字段(如自增ID),避免数据倾斜(某 Tablet 数据量是其他的 10 倍以上)。

<2> 索引结构优化

Doris 支持 Bitmap 索引、Bloom Filter 索引、倒排索引等多种索引类型,需根据查询场景选择:

  • Bitmap 索引:适用于低基数列(如性别、地域、商品分类)的等值查询与聚合(如 “统计各省份订单量”),可大幅减少扫描行数;
  • Bloom Filter 索引:适用于高基数列(如用户 ID、商品 ID)的 “IN” 查询与 Join 过滤,降低误判率(可通过fpp参数调整);
  • 倒排索引:适用于文本字段的模糊查询(如 “商品名称包含‘手机’”),提升全文检索效率。

需避免 “过度建索引”:索引会增加数据写入 / 更新开销(每次写入需同步更新索引),建议仅为高频查询条件字段建索引。

<3> 采用Colocate Join

当多个表的分桶键、分桶数量完全一致,且分区策略相似时,可通过PROPERTIES ("colocate_with" = "group_name")将它们标记为 Colocate 表。此时 Join 操作可在同一节点本地完成,无需跨节点数据 Shuffle,大幅降低网络 I/O 与内存开销。

(3) 查询的优化手段

<1> 确保分区剪裁生效

分区剪裁是减少数据扫描的关键,需满足以下条件:

  • 查询条件中包含分区键的等值、范围过滤(如create_time >= '2024-01-01');
  • 分区键过滤条件需是 “确定性表达式”,避免使用函数嵌套(如date_format(create_time, '%Y-%m') = '2024-01'可能导致剪裁失效,建议改为create_time >= '2024-01-01' AND create_time < '2024-02-01')。

<2> 利用单表物化视图加速

对于频繁执行的聚合查询(如 “按日统计商品销量”),可创建单表物化视图预先计算结果,查询时直接读取物化视图数据,避免重复聚合。例如:

CREATE MATERIALIZED VIEW mv_product_sales
AS 
SELECT product_id, date(create_time) AS sale_date, SUM(amount) AS total_sales
FROM orders 
GROUP BY product_id, date(create_time);

当查询 “某商品 2024 年 1 月销量” 时,Doris 优化器会自动匹配物化视图,无需扫描原始订单表。

(4) 执行上的优化

<1> 智能查询优化器(RBO + CBO)

Doris 新一代查询优化器采用 Cascades 架构,融合 RBO(基于规则)与 CBO(基于成本):

  • RBO:自动应用固定优化规则,如分区剪裁、列剪裁(仅读取查询所需列)、Join 重排(小表驱动大表)、子查询扁平化(将嵌套子查询转为 Join)等;
  • CBO:基于数据统计信息(如列基数、数据分布、NULL 值比例)计算不同执行计划的代价(CPU、I/O、内存),选择最优路径。例如多表 Join 时,CBO 会根据各表数据量选择 “BROADCAST JOIN” 或 “SHUFFLE JOIN”,避免低效 Join 策略。

建议定期更新统计信息(ANALYZE TABLE),确保 CBO 决策准确。当然了,他会自动统计的,如果没有统计,就是有问题的时候了,可以根据日志定位下具体的问题。

<2> 向量化执行与 Pipeline 执行模型

  • 向量化执行引擎:传统行式执行按 “单条数据 - 单次函数调用” 处理,向量化执行则按 “批量数据 - 单次函数调用” 处理,充分利用 CPU SIMD 指令集,减少函数调用开销与 CPU 上下文切换,对聚合、过滤等操作提升性能;同时结合列式存储与延迟物化(仅在需要时解析数据),进一步降低 I/O 与内存占用。
  • Pipeline 模型:将查询拆解为 “Scan → Filter → Join → Aggregate” 等多个 Pipeline 阶段,通过线程池异步执行各阶段任务,避免传统 “线程绑定任务” 导致的阻塞(如某阶段等待数据时,线程可处理其他任务),提升资源利用率与并发能力。

<3> MPP 架构与智能分布式执行

Doris 基于 MPP 架构实现分布式并行计算:

  • SQL 语句经 FE 解析后拆分为多个执行片段(Fragment),分发至不同 BE 节点并行执行;
  • 支持多种分布式 Join 策略:Colocate Join(本地 Join)、Broadcast Join(小表广播)、Shuffle Join(大表分片 Join),优化器根据表大小自动选择;
  • 支持动态负载均衡:执行过程中若某节点负载过高,可将部分任务迁移至空闲节点,避免单点瓶颈。

<4> 多级缓存与物化视图

Doris 构建了 “结果 - 中间结果 - 数据” 的多级缓存体系,减少重复计算与 I/O:

  • SQL Cache:缓存完全相同的 SQL 查询结果,适用于数据更新频率低、重复查询多的场景(如固定报表);
  • Query Cache:缓存查询过程中的中间聚合结果,后续同类查询可复用;
  • Page Cache:缓存解压后的列式数据,减少重复解压开销;
  • File Cache:针对存算分离场景,缓存远端存储(如 OSS)的数据,降低远程 I/O 延迟。

此外,异步多表物化视图支持 Join 场景的预计算,可定时刷新,查询时透明匹配,无需修改 SQL 即可享受性能提升,适用于复杂多表统计场景。

<5> 高并发点查优化

针对 QPS 超万的点查场景(如用户订单查询、商品详情查询),Doris 提供三项核心优化:

  • 行列混合存储:默认列式存储优化分析场景,点查时可触发行存读取(仅读取单条数据的所有列),减少 I/O 放大;
  • Short-circuit Plan:跳过 MPP 分布式调度流程,直接由单节点读取 Tablet 数据,缩短查询路径;
  • 全局 Prepared Statement:缓存 SQL 解析后的执行计划,避免重复解析开销,提升吞吐。

(5) 验证

  • 通过explain查看执行计划
  • 直接查看sql的执行日志和执行时间