Apache Doris Profile 深度解析:从获取到分析,解锁查询性能优化密码

发布于:2025-07-01 ⋅ 阅读:(17) ⋅ 点赞:(0)

在这里插入图片描述

在 Doris 数据库中,高效的查询性能是数据处理的关键。当我们遇到查询缓慢、资源消耗异常等问题时,Doris 提供的 Profile 工具就如同一位 “性能侦探”,能帮我们抽丝剥茧,找到问题根源。今天,我们就来深入聊聊如何分析 Profile,让 Doris 的查询性能更上一层楼。

一、Profile:解决查询性能的利器

Profile 是 Doris 用于记录和展示查询执行详细信息的强大工具,它以树状结构将查询计划的每个阶段(Operator)的执行时间、资源消耗等指标清晰呈现。通过 Profile,我们可以直观地了解查询的性能表现,判断哪些操作耗时过长,是否存在数据倾斜、网络延迟等问题,从而为优化查询性能、排查问题提供重要依据。无论是慢查询分析、性能调优,还是高并发场景下的瓶颈定位,Profile 的分析都贯穿其中,是 Doris 性能调优的核心依据。

对于用户而言,使用 Profile 有三个核心目标:精准找到查询的瓶颈点,进行基础的调优操作,以及基于瓶颈点判断需要哪些专业人员介入分析(找社区大佬支持)。掌握 Profile 的分析方法,能让你成为真正懂Doris性能优化的 “行家”。

二、获取 Profile:不同环境下的操作指南

想要利用 Profile 优化查询性能,首先要学会如何获取它。在不同的网络环境下,获取 Profile 的方法有所不同。

(一)Doris 集群能够正常访问外网

  1. 开启 Profile 收集参数enable_profile,该参数为 session 变量,不建议全局开启。在 mysql 客户端执行set enable_profile=true;,并通过show variables like '%profile%';确认变量是否正常开启(如果是压测时候,可以全局开启)。

  2. 执行对应 Query。需要注意的是,在集群有多个 FE 的情况下,要在开启 Profile 上报参数的 FE 上执行 Query,因为该参数并非全局生效(session变量,不加global,只在当前环境下生效)。

  3. 获取 Profile。访问执行对应 Query 的 FE HTTP 界面(HTTP://FE_IP:HTTP_PORT)的 QueryProfile 页面,点击对应 Profile ID 查看 Profile,还可以在 Profile 界面下载对应 Profile。

3.0.3 版本开始支持auto_profile_threshold_ms 变量,这样就不需要收集所有的query profile了,只需要收集超过指定时间的慢查询的profile

(二)Doris 集群访问外网受到限制

当集群不能正常访问外网时,需要通过 API 的方式获取 Profile(HTTP://FE_IP:HTTP_PORT/API/Profile?Query_ID=),IP 和端口是指执行对应 Query 的 FE 对应 IP 和端口。具体步骤如下:

  1. 前两步与正常访问外网时相同,即开启enable_profile参数并执行对应 Query。

  2. 找到对应 Query ID,通过show query profile "/";根据对应 Query 找到 Profile ID。

+-----------------------------------+-----------+---------------------+---------------------+-------+------------+------+------------+-------------------------------------------------------+
| Profile ID                        | Task Type | Start Time          | End Time            | Total | Task State | User | Default Db | Sql Statement                                         |
+-----------------------------------+-----------+---------------------+---------------------+-------+------------+------+------------+-------------------------------------------------------+
| 1b0bb22689734d30-bbe56e17c2ff21dc | QUERY     | 2024-02-28 11:00:17 | 2024-02-28 11:00:17 | 7ms   | EOF        | root |            | select id,name from test.test where name like "%RuO%" |
| 202fb174510c4772-965289e8f7f0cf10 | QUERY     | 2024-02-25 19:39:20 | 2024-02-25 19:39:20 | 19ms  | EOF        | root |            | select id,name from test.test where name like "%KJ%"  |
+-----------------------------------+-----------+---------------------+---------------------+-------+------------+------+------------+-------------------------------------------------------+
2 rows in set (0.00 sec)
  1. 查询 Profile 并将 Profile 重定向到一个文本中,使用命令CURL -X GET -u user:password http://fe_ip:http_port/api/profile?query_id=1b0bb22689734d30-bbe56e17c2ff21dc > test.profile

  2. 返回的 Profile 换行符为n,分析起来不方便,可以在文本编辑工具中将n替换为n,以便更好地查看和分析。

三、Profile 基础信息总览:快速定位问题方向

先来看一个 Profile 的基础信息示例:

Profile ID: 26ec8a4369b46ba-9af43a31cc4f5102
  - Task Type: QUERY
  - Start Time: 2025-03-31 17:23:47
  - End Time: 2025-03-31 17:25:51
  - Total: 2min4sec [总的耗时]
  - Task State: OK
  - User: root
  - Default Catalog: internal
  - Default Db: fine_bi_crossdata
  - Sql Statement: select * from view1 limit 100;
Execution Summary:
  - Parse SQL Time: 15ms
  - Nereids Analysis Time: 10ms
  - Nereids Rewrite Time: 51ms
  - Nereids Optimize Time: 30ms
  - Nereids Translate Time: 3ms
  - Workload Group: normal
  - Analysis Time: 10ms
  - Plan Time: 99ms [优化器的耗时,如果这个时间占据单个查询的比例过大,比如超过20%,需要联系社区同学分析]
    - JoinReorder Time: N/A
    - CreateSingleNode Time: N/A
    - QueryDistributed Time: N/A
    - Init Scan Node Time: N/A
    - Finalize Scan Node Time: N/A
      - Get Splits Time: N/A [如果是这块的占比时间比较高的情况,大概率是外表的问题]
        - Get Partitions Time: N/A
        - Get Partition Files Time: N/A
      - Create Scan Range Time: N/A
    - Get Partition Version Time: 9.561ms
    - Get Partition Version Count (hasData): 0
    - Get Partition Version Count: 1
    - Get Table Version Time: N/A
    - Get Table Version Count: 0
  - Schedule Time: 98ms
    - Fragment Assign Time: 1ms
    - Fragment Serialize Time: 21ms [这里也类似,如果耗时过多,请也得联系社区的同学分析了。很可能是有GC了]
    - Fragment RPC Phase1 Time: 75ms
    - Fragment RPC Phase2 Time: 1ms
    - Fragment Compressed Size: 3.92 MB
    - Fragment RPC Count: 24
  - Schedule Time Of BE: {...}
  - Wait and Fetch Result Time: 2min3sec
  - Fetch Result Time: 2min3sec [BE具体执行的耗时]
  - Write Result Time: 1ms [回写mysql的耗时,如果这块耗时过多,可能是客户端的瓶颈,分析一下结果集是不是过大]

从这些信息中,我们可以快速判断问题可能出在 FE 还是 BE 。通常情况下,95% 以上的主要耗时集中在Wait and Fetch Result Time。若 FE 出现问题,常见原因有 GC 问题、锁问题、CPU 打满等,这类问题与 FE 的集群负载密切相关,一旦确认是 FE 的问题,需要收集当时的 CPU、内存监控数据进一步分析。

四、定位瓶颈点:Merged Profile 汇总信息

为了更准确地分析性能瓶颈,Doris 提供了各个 operator 聚合后的 Merged Profile 结果。以EXCHANGE_OPERATOR为例:

EXCHANGE_OPERATOR  (id=4):
   -  BlocksProduced:  sum  0,  avg  0,  max  0,  min  0
   -  CloseTime:  avg  34.133us,  max  38.287us,  min  29.979us
   -  ExecTime:  avg  700.357us,  max  706.351us,  min  694.364us
   -  InitTime:  avg  648.104us,  max  648.604us,  min  647.605us
   -  MemoryUsage:  sum  ,  avg  ,  max  ,  min 
   -  PeakMemoryUsage:  sum  0.00  ,  avg  0.00  ,  max  0.00  ,  min  0.00 
   -  OpenTime:  avg  4.541us,  max  5.943us,  min  3.139us
   -  ProjectionTime:  avg  0ns,  max  0ns,  min  0ns
   -  RowsProduced:  sum  0,  avg  0,  max  0,  min  0
   -  WaitForDependencyTime:  avg  0ns,  max  0ns,  min  0ns
   -  WaitForData0:  avg  9.434ms,  max  9.476ms,  min  9.391ms

Merged Profile 对每个 operator 的核心指标做了合并,核心指标和含义包括:

指标名称 指标含义
BlocksProduced 产生的 Data Block 数量
CloseTime Operator 在 close 阶段的耗时
ExecTime Operator 在各个阶段执行的总耗时
InitTime Operator 在 Init 阶段的耗时
MemoryUsage Operator 在执行阶段的内存用量
OpenTime Operator 在 Open 阶段的耗时
ProjectionTime Operator 在做 projection 的耗时
RowsProduced Operator 返回的行数
WaitForDependencyTime Operator 等待自身执行的条件依赖的时间

我们可以通过以下简单方法快速定位瓶颈点:

cat profile_b112de34c7a94d2e-a6b773cc1db43602.txt  |grep ExecTime | grep max

找到max耗时最久的时间后,再回头在 Profile 中查找对应的算子,就能确定查询的性能瓶颈所在。

例如,通过上述方法找出慢的算子是AGG算子,后续就可以针对AGG算子进行深入分析和调优。

五、基础调优:对症下药,提升性能

Doris 中的查询主要分为两类,针对不同类型的查询,调优方法也有所不同。

(一)单表大宽表分析

对于单表的大宽表分析,优化方法可参考 Doris 查询优化秘籍(上篇):关键优化策略剖析,通过合理设计表结构、选择合适的索引等方式提升查询性能。

(二)多表关联复杂分析

多表关联的复杂分析中,70% - 80% 的性能问题是由 RuntimeFilter 和 JoinReorder 不合适导致的。

  • RuntimeFilter 调优:在 Profile 中搜索RuntimeFilterState关键字,如果发现IsPushDown = falseRuntimeFilter的状态为NOT_READY,可以通过设置set runtime_filter_wait_infinitely = true,重新验证是否是 RF 导致的性能问题。

  • Join 方式调优:在 Doris 中,shufflebroadcast是常见的数据分发方式,选择不当会影响查询性能。例如,当出现数据倾斜导致Shuffle性能极差时,可以通过指定broadcast join hint来优化,如SELECT COUNT(*) FROM orders o JOIN [broadcast] customer c ON o.customer_number = c.customer_number;

  • Join 顺序调优:Doris 中 JOIN 操作建议左表大于右表(或至少左表不小于右表),以优化查询性能。如果发现max的耗时主要在join上,可以查看join顺序是否合理。通过对比HASH_JOIN_OPERATOR(左表)和HASH_JOIN_SINK_OPERATOR(右表)的数据量情况,判断join顺序是否存在问题。若InputRows > ProbeRows,大概率join顺序不合理,此时可以请优化器的专家进行分析处理。

  • 并行度调整:当Schedule time占据大量查询耗时,通常是instance过多,导致rpc、序列化处理的数据量过大。这种情况下,可以考虑调小pipeline的并行度,如设置set global parallel_pipeline_task_num = 1,观察性能是否改善。

六、深入分析 Profile:常见问题与处理方案

通过 Execution Summary 部分,我们可以初步确定查询的瓶颈在 FE 还是 BE。若在 BE,我们可以重点分析各个算子的情况。在 2.1 版本的 Profile 经过 merge 后,界面较为精简,我们可以通过查看每个算子的查询时间来定位问题。一般来说,ExecTime最大的节点就是最耗时的节点,顺着这个 id 继续分析。如果各个算子耗时相差不大,说明没有明确的热点。

以下是一些常见问题的处理方案:

  • 热点在 nested loop join 上:尝试修改 sql,将 nested loop join 改为 hash join,可显著提升性能。

  • 热点在 join 上

    • 检查 join order 顺序,从条目数上判断是否合理。若右表条目数显著大于左表,或左右表数据量相近但右表列数显著大于左表,可能需要优化器同学介入。

    • 排查 Runtime filter,检查 rf 是否生效、等待时间是否合理,以及是否存在多余或无用的 rf。

    • 优化 join 列,尽量将 join 列和 group by 列建为非 null,能用定长列就不用变长列。

    • 评估 join 的 shuffle 方式是否合理,考虑使用Broadcastcolocate或优化Bucket shuffle

  • 热点在 agg 上:参考 join 列的优化方式,调整表结构,如将 group by 的列作为表的分桶列或分区列,可对单表聚合性能提升有显著效果。

  • scan 上慢

    • 检查表引擎类型,优先选择查询性能较好的duplicate key引擎。

    • 使用select 分桶列,count(*) from table group by 分桶列 order by count(*) desc limit 100;检查分桶是否有数据倾斜问题。

    • 注意 key 列的顺序,因为 Doris 底层存储引擎按 key 列排序存储,合理的 key 列顺序有助于快速二分查找。

    • 观察表的 compaction 情况,找到慢 scan 的 tablet,查看 compaction 链接,若存在慢副本,可通过set use_fix_replica绕过,并联系官方同学分析原因。

Profile 是 Doris 性能优化的关键利器,掌握它的获取、分析和调优方法,能让我们在面对查询性能问题时游刃有余。希望通过本文的分享,大家都能成为 Doris 性能优化的高手!如果你在使用 Profile 的过程中还有其他问题或经验,欢迎在评论区留言交流~


网站公告

今日签到

点亮在社区的每一天
去签到