恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
SAP HANA高频短查询排查:从捕获请求统计到PLV执行计划分析
首页
资讯中心
/
SAP HANA高频短查询排查:从捕获请求统计到PLV执行计划分析
SAP HANA高频短查询排查:从捕获请求统计到PLV执行计划分析
发布时间:2026/10/13 20:47:22
周五下午三点某数据平台的运维群里开始有人喊系统卡了。我登录 SAP HANA 看了一眼CPU 已经冲到 85%可昂贵的语句追踪里一条慢 SQL 都没有——单条执行都低于 1 秒。这个场景在 SAP HANA 的故障排查里太典型了真正拖垮系统的往往不是那几条明显的慢 SQL而是大量高频短查询的累积。要抓住它们得打开 Capture Request Statistics要读懂它们为什么慢又得把执行计划导成 PLV 文件用 VS Code 打开逐节点分析。这篇文章就把这套完整流程写下来。1. 为什么默认的昂贵语句追踪抓不住隐形慢 SQL1.1 昂贵语句追踪的 1 秒阈值陷阱SAP HANA 默认并不是什么都不记录它有一套叫 Expensive Statement Trace 的机制。这套机制看名字就知道专门记录执行得比较贵的语句。问题是它有一个硬性的执行时间阈值在indexserver.ini配置文件的[expensive_statement]段里参数叫threshold_execution_time默认值是 1000000 微秒也就是 1 秒。这意味着什么只有单次执行时间超过 1 秒的 SQL 才会被记录到昂贵语句日志里。很多运维同学排查慢 SQL 时习惯先看这个日志结果发现里面空空如也于是得出数据库没有慢 SQL的结论。但线上业务的真实情况往往是单次 100 毫秒的查询每秒被调 500 次一分钟累计占用数据库 CPU 的时间就是 300 秒。单拿出来哪一条都不够昂贵标准合在一起却能把整个实例拖垮。这就引出一个非常关键的观点慢 SQL 的定义不能只看单次耗时还要看执行频率和累计资源消耗。昂贵语句追踪本质上是一个事后告警工具适合人工抽查不适合做全量画像。想看清系统里到底跑了什么需要的是另一套能力——全量请求捕获。1.2 高频短查询如何慢慢拖垮系统高频短查询的最可怕之处不是每一次执行有多重而是它的累积效应。举个例子一个查询单次 50 毫秒执行 2000 次总耗时是 100 秒。这 100 秒里包含了对 CPU 的占用、内存的申请释放、计划缓存的查找和更新、结果集的序列化。如果并发高还会放大锁等待和线程排队。更隐蔽的是大量短查询会不断冲击执行计划缓存导致真正需要复用的好计划被频繁换出整体命中率下降让每条 SQL 的平均编译开销上升。用户体感就是系统整体变卡但抓单条 SQL 又抓不到。这类问题在接口型业务里最常见。前端轮询接口、定时任务高频扫描、报表工具反复拉取同一段数据都会产生这种隐形慢 SQL。它们不会写进昂贵语句日志也不会触发告警只会让 CPU 慢慢爬升直到某一天高峰期扛不住。1.3 什么场景值得开捕获Capture Request Statistics 的核心价值在于它把所有经过 SQL 引擎的请求都记录下来无论快慢。这样你拿到的不是几个典型样本而是一段时间内的完整请求画像。我一般在三类场景下会主动开启捕获。第一类是定期的性能巡检不需要等出故障先抓一到两天的全量数据做基线第二类是系统上线前后的对比确认新功能或新版本有没有引入异常的查询模式第三类是说不清哪里慢的疑难杂症没有明确慢 SQL但整体 CPU 或响应时间异常这时候必须靠全量数据还原现场。2. 打开 Capture Request Statistics参数、落表和性能代价2.1 三步开关命令、验证与生效范围打开 Capture Request Statistics 的操作非常轻量一条 ALTER SYSTEM 语句就能完成。在目标租户库执行ALTER SYSTEM ALTER CONFIGURATION (indexserver.ini, SYSTEM) SET (sql, capture_request_statistics) true WITH RECONFIGURE;注意几个细节。第一SYSTEM表示在集群级别修改配置这个配置会广播到所有 indexserver 节点在有多节点、多租户的架构下不需要逐台登录设置。第二WITH RECONFIGURE必不可少它让配置立即生效否则只是写入了配置文件要等实例重启才生效。第三这个参数作用在 indexserver 进程上所以要在目标租户库执行而不是在 SYSTEMDB 里执行了事。设置完成后先确认一下生效状态SELECT FILE_NAME, SECTION, KEY, VALUE FROM SYS.M_CONFIG WHERE FILE_NAME indexserver.ini AND KEY capture_request_statistics;看到 VALUE 为 true就说明开关已经生效。此时系统里的请求会开始往统计表写入数据。2.2 捕获数据落在哪两张统计表的关键字段开启捕获后数据落在_SYS_STATISTICS模式下的两张核心表里。一张是REQUESTS_CAPTURED记录每一次请求的执行概况另一张是STATEMENTS_CAPTURED保存 SQL 语句文本。两者通过STATEMENT_KEY字段关联。REQUESTS_CAPTURED里我最常用到的字段有这些字段含义用途START_TIME请求开始时间做时间段过滤圈定业务高峰期DURATION_MICROSEC请求总耗时微秒计算平均耗时、总耗时STATEMENT_HASHSQL 文本哈希把相同文本的 SQL 聚合成一类STATEMENT_KEY语句唯一键关联到 STATEMENTS_CAPTUREDUSER_NAME执行用户过滤系统请求、定向分析业务用户APPLICATION_NAME应用名称定位到具体接口或客户端TOTAL_CPU_TIME请求消耗的 CPU 时间看资源消耗比耗时更直观这张表是典型的宽表字段很多。实际做分析时先抓住执行次数、总耗时、平均耗时、CPU 时间这四类就足够迈出第一步了。2.3 捕获的代价采样与窗口期建议先说结论Capture Request Statistics 有额外开销但通常可控。每次请求结束后数据库需要把统计信息写入统计表这个动作本身会消耗一定 CPU 和 IO。特别是在每秒几千次短查询的高并发场景写入放大效应会比较明显。所以我不建议把这个开关常年常开更推荐窗口期狩猎的做法。比如设定 30 分钟到 2 小时的捕获窗口覆盖业务高峰或者做 1 到 2 天的全量捕获用于季度巡检。捕获结束后立刻关闭。如果确实需要长期监控可以研究一下采样相关参数把捕获比例调低但那样会损失全量数据的完整性属于权衡方案。我的经验是排查性能问题不需要 7x24 小时全量捕获抓一个完整的业务周期比如一个工作日下午加一个早晨高峰已经能覆盖大多数典型问题。3. 从统计表里捞出真正值得优化的 Top SQL3.1 第一刀按 SQL 指纹做总耗时聚合数据抓下来了直接一条条看肯定不现实。第一步一定是聚合。按什么维度聚合我建议按STATEMENT_HASH做分组这个字段相当于 SQL 的指纹不同文本但结构相似的语句会落在不同的哈希上归并起来非常干净。下面这条查询是整个过程的核心建议直接收藏SELECT RC.STATEMENT_HASH, COUNT(*) AS EXECUTION_COUNT, SUM(RC.DURATION_MICROSEC) / 1000000 AS TOTAL_DURATION_SEC, AVG(RC.DURATION_MICROSEC) / 1000 AS AVG_DURATION_MS, MAX(RC.DURATION_MICROSEC) / 1000 AS MAX_DURATION_MS, SUM(RC.TOTAL_CPU_TIME) / 1000000 AS TOTAL_CPU_SEC FROM _SYS_STATISTICS.REQUESTS_CAPTURED RC WHERE RC.START_TIME ADD_SECONDS(CURRENT_UTCTIMESTAMP, -3600) GROUP BY RC.STATEMENT_HASH ORDER BY TOTAL_DURATION_SEC DESC LIMIT 20;为什么排序用 SUM 而不是 MAX这是很多初学者容易犯的错。MAX只能告诉你最极端的那一次有多慢如果把所有资源都用来优化这一条很可能是在大海捞针而SUM把执行次数和单次耗时做了乘法直接量化了这条 SQL 在这段时间内总共消耗了多少数据库时间。优化掉的每一秒都是实打实的系统吞吐量提升。3.2 第二刀关联出 SQL 文本拿到哈希排名后下一步是把 SQL 文本捞出来。哈希只是一个代号你不知道具体是哪个查询。通过STATEMENT_KEY关联到STATEMENTS_CAPTURED表就能看到完整的语句内容SELECT SC.STATEMENT_STRING, RC.STATEMENT_HASH, COUNT(*) AS EXECUTION_COUNT, SUM(RC.DURATION_MICROSEC) / 1000000 AS TOTAL_DURATION_SEC FROM _SYS_STATISTICS.REQUESTS_CAPTURED RC JOIN _SYS_STATISTICS.STATEMENTS_CAPTURED SC ON RC.STATEMENT_KEY SC.STATEMENT_KEY WHERE RC.START_TIME ADD_SECONDS(CURRENT_UTCTIMESTAMP, -3600) GROUP BY RC.STATEMENT_HASH, SC.STATEMENT_STRING ORDER BY TOTAL_DURATION_SEC DESC LIMIT 20;执行这条查询时我建议多等几秒因为聚合的数据量可能很大。如果同时抓了多个节点的数据最终统计表里是整合后的结果不需要手动合并。拿到 SQL 文本后先肉眼扫一遍 WHERE 条件、JOIN 条件、子查询结构很多问题在这一步已经能猜个七八分。真正的确认还得靠执行计划。3.3 快速通道用 M_EXECUTION_STATISTICS 应急看最近请求有一种情况不需要开 Capture Request Statistics你只想看看最近几分钟系统在跑什么比如正在处理一个实时故障。这时候可以查询系统视图SYS.M_EXECUTION_STATISTICS它记录了最近实际执行过的请求而且直接带有STATEMENT_STRING字段连关联都省了。SELECT STATEMENT_STRING, COUNT(*) AS EXECUTION_COUNT, SUM(DURATION_MICROSEC) / 1000000 AS TOTAL_DURATION_SEC, AVG(DURATION_MICROSEC) / 1000 AS AVG_DURATION_MS FROM SYS.M_EXECUTION_STATISTICS WHERE START_TIME ADD_SECONDS(CURRENT_UTCTIMESTAMP, -900) GROUP BY STATEMENT_STRING ORDER BY TOTAL_DURATION_SEC DESC LIMIT 10;但要提醒一句这个视图是个内存环只保留最近一段时间或最近一部分请求容量有限不适合做历史分析和完整画像。它的定位是应急快照用于快速确认现在到底在跑什么。真正要写分析报告、做趋势对比还是得靠 Capture Request Statistics 落表的数据。3.4 顺手做体检执行次数、平均耗时、CPU 占比除了总耗时排名我通常还会顺手分析三个维度因为它们能反映不同类型的性能问题。执行次数特别高但平均耗时很低的 SQL往往是接口轮询或者循环调用优化思路是缓存结果、减少调用次数或者改批量查询平均耗时高但执行次数低的 SQL一般是复杂报表或大范围扫描优化思路是加过滤条件、拆分查询、优化 JOIN 顺序CPU 时间占比异常高的 SQL即使耗时不高也可能是大量运算、函数处理或类型转换导致的这类问题会在 CPU 挂高时特别明显。这三个维度的分析不需要额外查询上面的聚合 SQL 已经包含了相关字段只需要改变排序和观察角度。4. 把执行计划导出 .plv用 VS Code 打开4.1 统计回答是谁执行计划回答为什么前面做的所有工作都是在回答一个问题系统里哪些 SQL 消耗最大。这是一个定位的过程。但要真正解决问题必须回答下一个问题这些 SQL 为什么慢是表扫描走了全表是 JOIN 顺序有问题还是 WHERE 条件里的函数导致索引失效回答为什么靠执行计划。SAP HANA 的执行计划可视化文件就是 PLV全称 Plan Visualization。它把优化器生成的算子树转换成图形界面每个节点展示算子类型、消耗时间、处理行数、具体属性。对于熟悉节点阅读的人来说一张 PLV 比几千行日志都直观。4.2 产出一条 .plv 的两种常见方法第一条路径是在 SQL 控制台里用EXPLAIN PLAN语句直接生成执行计划。比如EXPLAIN PLAN FOR SELECT ORDER_ID, CUSTOMER_NAME, TOTAL_AMOUNT FROM ORDER_HEADER WHERE ORDER_DATE 2024-01-01 AND ORDER_DATE 2024-02-01;执行后控制台会返回一个结果集里面按层级列出了算子树。在 SAP HANA 的 Database Explorer 里可以在这个结果面板上找到导出计划或Visualize Plan之类的按钮把计划保存成.plv文件。第二条路径更直接在 Database Explorer 里打开某条 SQL 语句的执行历史找到具体某一次执行直接下载对应的执行计划文件。这种方式拿到的通常是那份实际执行过的计划包含真实行数和耗时比纯估算计划更有诊断价值。需要特别注意一个坑EXPLAIN PLAN FOR生成的是优化器估算的计划反映的是数据库认为应该怎么执行而不是实际上怎么执行。在统计信息不准确或查询过于复杂时估算计划和实际计划可能差别很大。定位问题时优先使用实际执行计划。4.3 VS Code 环境与扩展配置拿到 .plv 文件后用文本编辑器打开只能看到一堆 JSON真正舒服的打开方式是使用可视化渲染工具。VS Code 里可以直接做到这一点。先在扩展市场搜索并安装 SAP 官方提供的 SAP HANA Database Explorer 扩展。安装完成后VS Code 会把.plv文件关联到该扩展的执行计划可视化视图。直接点击文件名打开就能看到图形化的算子树。如果扩展装好了双击还是显示 JSON不需要卸载重装右键点击文件选择 Open With然后手动选择 SAP HANA 相关的执行计划查看器即可。这种手动关联在第一次使用时很常见。4.4 打开失败和渲染异常的排查逻辑没有扩展时的表现最直接文件会以纯文本 JSON 打开一眼就能识别。有扩展但打不开可分为三种情况。第一文件后缀不是.plv可能是.json或.txt需要右键手动关联第二文件内容不完整比如从控制台复制时只复制了一部分 JSON这种情况需要重新导出完整文件第三版本兼容性问题数据库版本和 VS Code 扩展版本跨度太大时某些节点属性可能显示不全但通常不会完全打不开。一个比较实用的兜底方案如果 VS Code 的环境一直配置不好可以把 .plv 文件直接拖入 SAP HANA Database Explorer 的网页版网页版同样内置了 PlanViz 渲染器功能不输 VS Code。5. 读懂一张 PLV五个必须看的抓手5.1 先看算子树从根到叶子的阅读顺序打开一张 PLV第一眼看到的是纵向或横向的算子树。根节点在最上端或最左端叶子节点在底部或最右端数据从叶子往根方向流动。每一层节点都代表一个具体的操作全表扫描、索引查找、JOIN、聚合、排序、投影等等。我最先看的是根节点。总耗时就放在那里它旁边的耗时条通常很夸张。如果根节点显示 85% 的耗时都来自底下某个子树那问题就不需要继续猜了——所有注意力都应该投到那个子树里去。这个阅读顺序看起来简单但很多人在 PLV 里迷路的唯一原因就是从叶子开始看结果被一堆细枝末节的操作带偏。正确做法永远是先看根再看最耗时的分支最后才收缩到具体算子。5.2 行数估算值和实际值相差一个数量级就要警惕PLV 里每个节点都标注了行数。这可能是整张计划里最有价值的数据。看的时候要区分两种行数估算行数Estimated Rows和实际行数Actual Rows。估算行数是优化器基于统计信息推算出来的实际行数是查询真正处理的数据量。当两者非常接近时说明优化器的判断靠谱执行计划整体可信当两者相差超过一个数量级时说明统计信息已经过期、直方图不准确或者存在复杂表达式让优化器无法准确估算。这种偏差是性能问题的温床可能直接导致优化器选择了错误的 JOIN 顺序或扫描方式。在实际计划里发现这类偏差下一步就是刷新相关表的统计信息比如执行ANALYZE相关操作然后再对比新计划。很多莫名其妙慢的查询刷新统计信息后自动就好了。5.3 三类重点算子扫描、Join、聚合算子种类很多但性能诊断中需要聚焦的其实只有三类。第一类是 TABLE SCAN。看到一个大的 TABLE SCAN 节点时要立刻确认表是列存还是行存过滤条件下推到了哪一层以及有没有做分区裁剪。最坏的情况是整张几亿行的列存表从头扫到尾那基本等于把查询速度的下限拉满了。第二类是 JOIN。看 JOIN 类型是 HASH JOIN 还是 NESTED LOOP JOIN然后看驱动表是哪一边。通常驱动表应该选小表或过滤后数据量小的一方如果顺序反了耗时会成倍增长。还要确认 JOIN 条件是否完备缺了条件的笛卡尔积是性能杀手这是新手最容易踩的坑。第三类是聚合和排序。GROUP BY 的字段数量直接影响分组开销字段越少越快排序操作如果出现在大数据量节点上会消耗大量内存和临时空间。三类算子可以整理成一张自查表分析任何执行计划时都可以对着过一遍算子类型关注点常见性能问题TABLE SCAN列存/行存、过滤下推、分区裁剪全表扫描、谓词未下推JOINJOIN 类型、驱动表顺序、条件完备笛卡尔积、驱动表过大AGGREGATION / SORTGROUP BY 字段数量、排序数据量分组键过多、内存溢出5.4 谓词下推、分区裁剪和隐式转换这三个概念听起来抽象但它们的共同点是决定了扫描阶段到底碰了多少数据这是查询性能的根基。谓词下推就是 WHERE 条件里的过滤动作能不能提前发生。理想情况下过滤应该在扫描叶子节点时就把大部分行挡掉而不是把大量数据一路传到上层再过滤。在 PLV 里如果发现一个很大的过滤条件出现在树的上层节点而不是紧贴着扫描节点就说明下推失败要对执行计划做进一步分析。分区裁剪更直白如果表按日期分区WHERE 里指定了日期范围执行计划应该只扫描对应分区。如果 PLV 显示扫描了全部分区说明分区键没有被有效利用。隐式转换是导致前两个问题失效的元凶。最典型的表现是 WHERE 条件里对索引列或分区列套上了函数或者字段类型不匹配导致数据库悄悄做了类型转换。比如WHERE TO_CHAR(ORDER_DATE) 2024-01-15这会让数据库放弃日期分区裁剪和索引扫描老老实实全表扫描。这一类问题在 PLV 上往往不是一眼能看到的名字而是扫描节点行数异常偏大这个现象。6. 一个真实案例高频短查询的完整排查链路6.1 现象每天下午三点准时变慢接手过一个某数据平台的性能问题现象非常规律每天下午三点半左右系统开始变慢持续大约四十分钟其他时段一切正常。初期的排查方向集中在后台批处理上因为临近下班时间通常有汇总任务在跑。但从应用监控来看批处理按时启动了数据库的昂贵语句日志里也没有任何超过 1 秒的查询监控面板上一片祥和用户却切切实实在报卡顿。这个矛盾点正是我前面提到的隐形慢 SQL的典型特征。当时决定不再猜了直接开 Capture Request Statistics 做全量捕获。开关在三点前打开持续了一个半小时捕获了一整个异常时段。6.2 捕获数据给出的第一轮证据捕获结束后用前面那套聚合查询把数据拉出来结果完全出乎意料。Top 排名前四的 SQL 全是 SELECT 语句分别来自同一个订单查询接口总执行次数惊人——四类语句加起来在 90 分钟内执行了近 2 万次平均单次 80 毫秒左右。单看单次耗时完全不差但累计总耗时排到了整个系统第一位。顺着应用名追过去发现这个接口被前端页面设置成了每 3 秒轮询一次而且一个页面同时会触发多张报表卡片每张卡片都调这个接口。轮询频率高本身没问题问题在于这四类查询内部都藏着同一个性能隐患——它们对订单主表的扫描方式非常低效几亿行的列存表每次查询都从最近的分区开始扫。6.3 PLV 揭示的根因函数包裹索引列把其中耗时最高的一条 SQL 导出执行计划在 VS Code 里打开 PLV。算子树一眼看过去叶子节点是一个巨大的 TABLE SCAN扫描行数几乎是全表量级而根节点耗时占比高达 70%。过滤条件确实存在但它对一个时间字段做了格式化处理写成了形如TO_CHAR(ORDER_DATE, YYYY-MM-DD) 2024-06-01的条件。这正是典型的隐式转换问题。时间字段是分区键理论上只需要扫一个分区但函数包裹让优化器无法把等值条件转换成范围扫描最终选择了扫描大量分区甚至全表。类似的问题还有把字符型字段转成数值型再比较同样会让索引失效。读 PLV 到这里根因已经非常清楚了。SQL 本身逻辑没问题是写法没有尊重字段的原始类型等于亲手把优化器的手脚绑住了。6.4 改写 SQL 之后的效果对比修复方式是重写 WHERE 条件把函数移到等号右侧变成对常量做处理-- 优化前 WHERE TO_CHAR(ORDER_DATE, YYYY-MM-DD) 2024-06-01 -- 优化后 WHERE ORDER_DATE TO_TIMESTAMP(2024-06-01 00:00:00) AND ORDER_DATE TO_TIMESTAMP(2024-06-02 00:00:00)改完再看执行计划叶子节点的扫描行数直接下降到原来的几十分之一分区裁剪生效了。对比捕获数据同一接口查询的平均耗时从 80 毫秒降到 9 毫秒由于执行次数不变该时段的总耗时下降了接近 90%。三天后观察 CPU 趋势下午三点半的峰值完全消失。事后复盘给我的启示是很多高频短查询的优化收益被严重低估。一条查询优化掉 70 毫秒听起来不刺激但乘上每小时几千次的执行频率就是肉眼可见的 CPU 资源释放。7. 捕获与诊断中容易踩的坑7.1 坑一开关开了就不关统计表疯涨Capture Request Statistics 一旦开启统计表的数据量增长很快。高并发场景下一小时就可能写入几十万条记录长期不关会导致_SYS_STATISTICS模式下的表膨胀反过来影响系统性能。我的做法是把开启操作和关闭操作写在同一条运维记录里并且给捕获窗口设置一个明确的结束时间。比如在操作备注里写15:00 开启预计 17:00 关闭。如果确实需要长时间分析也要规划定期清理统计表的策略避免磁盘和内存被历史数据占满。7.2 坑二排名只看 MAX漏掉高累计消耗分析捕获数据时如果只按 MAX 排序会把注意力引向那些偶尔慢一次的查询比如月末跑批、定时报表。真正持续消耗系统资源的往往藏在 SUM 排名的前列。这两种查询的优化价值完全不同。单次 2 秒、每天跑 5 次的报表查询优化到 1 秒每天省 5 秒单次 50 毫秒、每分钟跑 200 次的接口查询优化到 25 毫秒每分钟省 5 秒一天下来节省的时间是前者的几十倍。所以不管看哪份报告我都习惯把 SUM 作为第一排序字段MAX 只作为参考。7.3 坑三把 EXPLAIN PLAN 的估算计划当成实际表现EXPLAIN PLAN输出的是优化器认为应该怎么跑的计划属于预演性质实际执行时因为数据分布、内存、并发等因素计划可能完全变样。我曾经犯过这个错误优化好一条 SQLEXPLAIN PLAN 看起来非常完美但上线后性能没有提升一查实际执行计划优化器运行时选择了另一条低效的路径。原因是对某张大表的统计信息严重过期优化器在真实环境中重新评估后放弃了预演时选定的 JOIN 顺序。所以验证优化效果时不要停留在 EXPLAIN PLAN 层面最好拿到实际执行计划对比或者直接观察捕获数据中该 SQL 的真实耗时变化。PLV 文件如果来自实际执行会标注实际行数和耗时可靠性远高于纯估算计划。7.4 我的习惯把捕获做成季度巡检的一部分这套方法我并不仅用于应急排查更多时候用于例行巡检。每季度挑一个业务周期开启一到两天捕获把 Top SQL 清单导出来存档再和上一轮的结果对比。哪些新查询进入了 Top哪些旧查询的耗时在下滑哪些查询的执行次数在悄悄上涨都一目了然。这个习惯帮我在故障发生前发现过不少隐患。比如某条老查询本来平均 20 毫秒连续两个季度慢慢涨到了 120 毫秒单次不慢总量却翻了好几倍顺着统计表一查原来是底层表数据量膨胀现有索引选择性变差。如果等到用户报障再查可能已经是高峰期扛不住的临界点。我自己最深的体会是诊断 SAP HANA 性能问题Capture Request Statistics 和 PLV 是一对组合拳前者负责把真凶从海量请求里捞出来后者负责把犯罪动机从算子树里挖出来。缺了第一步你只是在瞎猜缺了第二步你知道是谁却不知道怎么改。按这套流程走下来大多数性能问题都能在半小时内给出明确结论。