mcpField
D
debug-slow-sql

debug-slow-sql

github.com/arc-mcp开发239229 次安装2 天前更新
代码仓库

关于 debug-slow-sql

此技能通过 ARC-1 诊断 ABAP SQL 或 Fiori Elements OData 请求变慢的原因,面向维护 SAP 应用的开发人员。它按成本逐步检查请求耗时、CDS SQL 与代码路径,并在需要时升级到性能追踪。

主要功能

  1. 01检查 OData 请求耗时分布
  2. 02查看 CDS 编译后的 SQL
  3. 03测量查询执行时间与结果行数
  4. 04分析 ABAP 追踪中的热点路径
  5. 05启用并引导读取 ST05 SQL 追踪
  6. 06运行性能类 ATC 静态检查

适用场景

  1. 01定位变慢的 OData 或 Fiori 列表根因
  2. 02排查长时间运行的 CDS 视图或报表
  3. 03分析负载下超时或转储问题

MCP 相关

该技能通过 ARC-1 运行 SAP 诊断并逐级深入性能追踪;追踪记录与执行计划可能需要在 SAP GUI 或 Fiori 中查看。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/arc-mcp/arc-1 --skill debug-slow-sql

安装后在 Claude Code 中输入/debug-slow-sql确认已加载。

详细介绍

调试慢速 SQL / OData

找出 ABAP SQL 或 Fiori-Elements OData 请求缓慢的根本原因并提出修复方案——先使用 ARC-1 进行诊断(无需 GUI),只有在需要更深入的信号时才升级到 SAP GUI / Fiori 应用。目标不是只说“很慢”,而是弄清楚为什么:是哪条语句、扫描了什么,以及要修改什么。

当用户报告报表/事务处理缓慢、OData/Fiori 列表缓慢、CDS 视图运行时间过长、负载下超时/转储,或“这个查询从……之后就变慢了”时,请使用此流程。


输入信息(只询问缺失的内容)

  • 慢的是什么——以下之一:OData URL(从浏览器的 Network 标签页复制)、CDS 视图 / DDLS 名称、ABAP 程序 / 类 / 报表、事务码,或表 + 访问模式。
  • 有多慢 / 多频繁——单次调用缓慢、负载下缓慢,还是偶发。(这决定是进行单请求分析还是汇总分析。)
  • 能否复现?——用户能否按需再次触发(启动实时跟踪所需)?在哪个系统(DEV/QA/PROD),以哪个 SAP 用户身份?
  • 近期是否有变更?——新代码、新增数据量、传输请求、索引删除。可快速缩小搜索范围。

如果用户只含糊地说“X 很慢”,请先获取 OData URL 或对象名称——以下所有步骤都以此为依据。


诊断阶梯——找到能解释问题的那一级就停止

自上而下逐级排查。每一级的成本都低于下一级,而且通常能告诉你是否需要继续深入。

确认可达性——不要承诺无法完成的计划。 第 3–4 级(分析器、ST05)需要 SAP_ALLOW_WRITES 才能启动,还需要 S_ADT_RES 对跟踪资源具有 URI 覆盖权限,以及跟踪工具的后端授权 (使用 STAUTHTRACE 确认)——且 NW 7.50 上没有这些工具。如果启动时返回 writes disabled 或 403,请说明情况并停在第 2 级:odata_perf + cds_sql + SAPQuery 已足以在无需 GUI 的情况下确定数据库相关的根本原因。第 3–4 级(确切语句 + 执行计划)取决于 Basis/配置;此时应将下方精确的 ST05/SAT 操作步骤交给用户,而不要假装已经拿到了执行计划。

0. 初步了解(不执行)
  • SAPContext(action="deps", type="<type>", name=…) / SAPRead(type="DDLS", name=…)——读取 CDS/ABAP 源码。测量前先目视检查常见问题:LIKE '%term%'(前导通配符 = 无法使用索引)、没有对键使用 WHERE 条件的 SELECT … FROM、SELECT *、LOOP 中嵌套 SELECT(N+1)、 客户端筛选、缺少 FOR ALL ENTRIES 前置检查、导致全表扫描的计算字段。
  • SAPContext(action="impact", type="DDLS", name=…)——CDS 堆栈(投影 → 基础视图 → 表)。慢速视图通常只是基于繁重基础视图构建的薄投影。
  • 查找生成器,而不只是字面 SQL。 缓慢的 LIKE '%…%'/扫描通常是生成的——由搜索帮助、SADL/RAP 或框架生成,而非手写,因此用 grep/where-used 搜索字面的 SELECT 往往一无所获。应追踪生成器:对于值帮助 / 类型预输入界面,通过 SAPSearch/SAPNavigate/SAPRead 检查搜索帮助 (DD30L.SELMETHOD + FUZZY_SEARCH、DD32S 字段)及其 DSH/SADL 类(CL_DSH_*、F4→WHERE 转换)。对于 OData 服务,找到其实现:V4/RAP 绑定 → SAPRead(type="SRVB", name=…) → 服务定义 → CDS 视图(然后使用第 2 级的 cds_sql)。绑定(SRVB)名称通常与 URL 中的服务路径不同——如果 SRVB 返回 404,请使用 SAPSearch 搜索服务名称以找到实际绑定,或直接读取服务定义(SRVD)中的 expose … as 实体。传统 SEGW / Gateway V2 服务没有 CDS → 查找 DPC 类(SAPSearch "<SERVICE>_DPC*",读取其 *_get_entityset / *_get_entity / expand / resolve_navigation_path 方法),并跳过第 2 级。(不要将 SE91/WBMESSAGES 与搜索帮助路径混淆:前者会将一个消息类加载到内存中并使用 CS 搜索;搜索帮助路径则会发起真正的数据库 LIKE 查询。)
1. 时间都花在哪了?(一次低成本调用)

对于 OData / Fiori 请求:

SAPDiagnose(action="odata_perf", url="/sap/opu/odata4/sap/…/Entity?$filter=…")

读取 verdict:

  • db(gwappdb 占主导)→ 成本在 CDS/SQL 查询 → 转到第 2 阶。
  • app(gwapp ≫ gwappdb,或不存在 gwappdb)→ ABAP/SADL 逻辑,不是数据库。不要 用 ST05 查找慢查询——找出实现该服务的内容(第 0 阶),并对其进行跟踪(第 3 阶)。典型 问题是 $expand N+1——分别使用和不使用 $expand/$select 对 URL 重新探测,并观察 gwapp 的变化,即可隔离问题。
  • framework(gwfw;在 7.50 上通常只有 gwhub)→ 元数据 / 首次调用 / 冷缓存 → 缓存预热后重新探测。 如果只有 gwhub,说明你还无法区分数据库和应用;如果不只是冷缓存,就继续深入进行跟踪。
  • auth(icfauth)→ ICF/DCL 授权开销。
  • unknown → 没有可用的 Gateway 耗时数据;确认该 URL 是 SAP 主机上的 OData/Gateway 服务。

(odata_perf 需要 SAP_ALLOW_DATA_PREVIEW;url 必须是 ARC-1 连接到的 SAP 主机上 /sap/opu/odata 或 /sap/opu/odata4 下的相对主机 OData 路径——其他路径会被拒绝。它会执行 GET,因此请使用 Network 选项卡中的 实体/列表请求,而不是 $batch POST。)

2. 数据库受限 → 查看并测量实际 SQL
  • SAPDiagnose(action="cds_sql", name="I_TheView") — CDS 编译成的原生 CREATE VIEW(只读;已在 7.50/758/816 上验证)。 现在可以看到实际的联接、CAST、COALESCE,以及子视图是否引入了额外的表。
  • SAPQuery(sql="SELECT … FROM <cds-or-base> WHERE <the filter>") — 返回 columns/rows 以及数据预览 指标:queryExecutionTimeMs、totalRows(匹配总数)、rowsReturned 和 executedQueryString。 使用慢请求中的实际筛选值运行:如果有用的结果很少,但 totalRows / queryExecutionTimeMs 很大, 就说明存在扫描/选择性问题。它不会显示 HANA 执行计划或缓冲区状态——这些请使用 ST05/HANA。SAPQuery 超时本身就是存在无界扫描的证据——记录超时作为信号,不要只用较小的 maxRows 重试。(自由格式 SQL 需要 SAP_ALLOW_FREE_SQL;通过 SAPRead(type="TABLE_QUERY") 执行多列 WHERE 需要 SAP_ALLOW_DATA_PREVIEW。)
  • 等值查询也慢?问题在视图,不在筛选条件。 如果使用精确条件 WHERE key = '…' 的 SAPQuery 和 LIKE '%…%' 一样慢(两者都要几十秒),那么 LIKE 只是个假线索——成本在 CDS 本身:宽泛的 SELECT DISTINCT、筛选条件无法作为起点的深层联接(筛选字段不是索引的首列),或聚合 / $count=true。 cds_sql 会显示联接顺序;解决方法是反转联接,让高选择性表作为起点,在列表投影中删减 DISTINCT/聚合,或在大规模扫描时去掉 $count=true——而不是改动 LIKE。
  • 对比信号:先探测 OData URL,再对底层 CDS/基础表运行 SAPQuery——如果 queryExecutionTimeMs 接近 OData 的 gwappdb,那么成本在数据库查询;如果 OData 很慢而查询很快,那么问题在上层的 SADL/框架层。要查看确切语句和执行计划,请继续深入到 ST05。
  • 建议采用 HANA 全文搜索 / CONTAINS / 模糊匹配修复?你无法通过 SAPQuery 对其进行 A/B 测试——ADT 自由格式端点仅支持 Open SQL,并会拒绝 CONTAINS(...) / … CP '*x*'(400 "(" is not allowed)。 应通过实际功能运行时的 ST05 跟踪,或一次性的 ABAP 探测报告来验证。首先确认表确实有全文索引: SAPQuery(sql="SELECT indexname, full_text FROM dd12l WHERE sqltab = '<TABLE>'") → full_text = 'X'。
3. 应用绑定 → ABAP 分析器跟踪(哪些代码、哪些表)
SAPDiagnose(action="traces")                                  # list recent profiler traces
SAPDiagnose(action="traces", id="<id>", analysis="hitlist")    # hottest call paths
SAPDiagnose(action="traces", id="<id>", analysis="dbAccesses") # which tables, counts, buffered?

dbAccesses 视图会告诉你请求访问了哪些表,以及访问频率(N+1 问题会表现为某张表的计数特别高)。hitlist 会告诉你 ABAP 热路径。ARC-1 可以自行启动分析器跟踪请求 — SAPDiagnose(action="trace_start", …),然后用 trace_requests 列出请求,并用 trace_cancel 清理 — 也可以在 SAT/ST12 中记录跟踪;然后用上文的 traces 操作列出/分析跟踪。

trace_start 本身会提示两项注意事项,请务必留意:(1)HTTP 跟踪会捕获用户接下来第一个匹配的 HTTP 调用,因此启动后,在用户完成复现之前,不要进行其他 ARC-1/MCP 调用 — 你自己的 ADT 调用会消耗这个捕获机会。(2)对于 HANA 上的 HTTP/OData 跟踪,分析器能力有限:hitlist/statements 通常为空(或报错 400 "Data is invalid…"),业务表会隐藏在 <DB Access from Kernel> 分类中 — dbAccesses 仅用于判断“是否访问了表 X、访问了多少次”;实际的 OData SQL 和计时信息请使用 ST05(第 4 阶段)。分析器最适合用于 ABAP 端代码的对话、报表和 RFC 跟踪。

4. 精确 SQL + 执行计划 → ST05 SQL 跟踪

ARC-1 可以启动/停止 ST05 SQL 跟踪,并为你提供记录入口(无法通过 ADT 读取记录 — SAP 没有 SQL 记录 API;记录查看需使用 TMC Fiori 应用 / SAP GUI ST05):

SAPDiagnose(action="sql_trace_state")                                   # is a trace already on?
SAPDiagnose(action="set_sql_trace_state", sqlOn=true, user="<SAPUSER>") # arm, filtered to the user (needs SAP_ALLOW_WRITES)
#   → user reproduces the slow request now ←
SAPDiagnose(action="sql_trace_directory")                               # SAP's "SQL Trace Analysis" deep-link
SAPDiagnose(action="set_sql_trace_state", sqlOn=false)                  # always disarm when done

然后读取记录(参见“SAP GUI / Fiori 升级处理”)。记录列表会显示精确的 SELECT、其持续时间、获取的行数、对象,以及(在 ST05 中)EXPLAIN / 执行计划和缓冲区状态。 758/816 上可用;NW 7.50 上不可用(/st05/trace ADT API 在该版本上返回 404 — 请使用 SAP GUI ST05)。

读取记录(没有 sql_trace_records/sql_trace_read ADT 操作 — sql_trace_directory 只返回查看器链接):打开深层链接(TMC“SQL Trace Analysis”)或 SAP GUI ST05 → Display Trace → 选择应用服务器和跟踪文件 → 按 Duration 降序排序 → 逐行读取 SQL 文本、Duration、Records(获取的行数)和 Object(表/视图);双击耗时最长的记录 → 选择 Explain 查看 HANA 执行计划。请留意:关联/文本表的额外访问(SADL 扩展)、重复的相同 SELECT(N+1),或 Records ≫ 可见行数(选择性)。

如果性能端点返回 403,提示“Service cannot be reached”,ARC-1 会显示 icf-service-inactive 提示 — 在 SICF 事务码中激活指定的 SICF 节点(跟踪界面使用 /sap/bc/stmc)。

5. 静态检查(随时可用)

SAPDiagnose(action="atc", type="<type>", name=…, variant="PERFORMANCE_DB") — 静态标记性能反模式(它无法捕获依赖数据的运行时 LIKE 扫描,但免费使用,而且能发现明显问题)。


SAP GUI / Fiori 升级处理(当 ARC-1 的无 GUI 信号不足以解决问题时)

ARC-1 在读取 SQL 跟踪记录和执行计划之前都无需 GUI——遇到这两种情况时,请升级处理。 明确告知用户需要打开什么,以及需要查看什么;或者,如果你有桌面端/Chrome MCP 且已获授权, 也可以自行操作(未经明确批准,绝不在 PROD 上操作)。

工具位置它能提供哪些 ARC-1 无法提供的信息
ST05(SQL/RFC/缓冲区/enqueue 跟踪)SAP GUI记录的 SELECT 语句及其耗时和行数;“Explain” → 数据库执行计划;相同/相似语句分组;缓冲区命中情况。判断“是哪条语句以及原因”的确凿依据。
SQL Trace AnalysisFiori 应用(sql_trace_directory 深层链接)在浏览器中查看相同的 ST05 记录(TMC)——SAP GUI 不可用时使用。需要启用 /sap/bc/stmc SICF。
ST12 / SATSAP GUI聚合后的 ABAP+SQL 组合跟踪——最适合通过一次捕获来判断应用和数据库的耗时分布。
DBACOCKPIT / HANASAP GUI / HANA Studio / DBeaverEXPLAIN PLAN、PlanViz、M_SQL_PLAN_CACHE、表/索引大小、缺失索引提示、优化器统计信息的新鲜度。HANA 侧的根本原因(列存扫描、未进行分区裁剪、统计信息过时)。
ST22 / SM50 / SM66SAP GUI转储(例如 TIME_OUT、TSV_* 内存转储),以及负载下哪些工作进程处于卡住状态。
SE11 / SE14SAP GUI表上的索引及其字段,以及较慢的 WHERE 子句是否匹配可用索引的前缀。
ABAP Cross TraceADT(/sap/bc/adt/crosstrace/*,758+)感知 RAP/OData 的跨层跟踪,包括 OData V4 请求类型——战略性的 ADT 原生记录读取器(ARC-1 后续工作;尚非工具)。

为 odata_perf 捕获 OData 请求: 浏览器开发者工具 → Network → 点击较慢的 $batch/实体 请求 → 复制主机之后的路径(例如 /sap/opu/odata4/sap/zsrv/…/Entity?$filter=…&$top=…)。该路径就是 url 参数。


根因目录(模式 → 确认 → 修复)

跟踪/SQL 中的症状可能原因确认方法常见修复方法
rows fetched 远大于显示的行数;耗时长全表扫描 / 选择性差cds_sql 显示没有带索引的 WHERE;SAPQuery totalRows 数值较大 / ST05 显示获取行数较多对带索引的字段添加 WHERE;添加二级索引(SE11);将筛选条件下推到 CDS 中
LIKE '%term%'前导通配符导致索引不可用查看 DDLS/ABAP 源代码使用搜索帮助 / 模糊搜索(HANA)/ 全文索引;固定模式的开头;预筛选
同一张表被访问数千次N+1(在 LOOP 中执行 SELECT)traces dbAccesses 显示对某张表的访问次数极多使用 FOR ALL ENTRIES / JOIN / 先全部读取再循环;RAP:预取
执行 SELECT *,但只使用 2 个字段过量获取cds_sql / 源代码仅选择所需字段;精简 CDS 投影
在 DEV 中很快,在 PROD 中很慢数据量 / 统计信息过时 / 执行计划不同比较 EXPLAIN 和表大小(DBACOCKPIT)刷新优化器统计信息;添加索引;分区
gwappdb 数据量小,但 OData 很慢SADL / 判定逻辑 / 虚拟元素 / 授权(DCL)odata_perf 判定为 app/auth;分析器 hitlist将逻辑移到数据库/CDS 中;简化 DCL;缓存;避免逐行处理 ABAP 虚拟元素
仅首次调用较慢元数据 / 冷缓存odata_perf 判定为 framework;预热后重新探测属于预期情况;预热;无需优化查询
负载下出现 TIME_OUT / 内存转储结果无界 / 缺少分页ST22 + ST05服务端分页($top/$skip);添加筛选条件;将工作分批处理

实例演示(真实案例,a4h S/4HANA 2023)

有人反馈“消息文本搜索界面很慢”。其背后的查询:

SAPQuery(sql="SELECT sprsl, arbgb, msgnr, text FROM t100 WHERE text LIKE '%error%'")
→ { totalRows: 12549, queryExecutionTimeMs: 49.086, rowsReturned: 100,
    executedQueryString: "SELECT … FROM T100 WHERE TEXT LIKE '%error%' … UP TO 100 ROWS" }

看一下:对非索引文本列执行前置通配符 LIKE '%…%',匹配了 12 549 行 → 全表扫描(由于模式以 % 开头,索引无法使用)。用户实际需要的结果只有几行。**修复方案:**去掉前置通配符(锚定搜索)/添加搜索帮助或全文索引/先使用索引字段预筛选。要查看 HANA 执行计划和获取的行数,请启用 ST05 跟踪(第 4 级),重现问题,然后打开目录中的深层链接。

这是简单情况——单表扫描,前置通配符确实是瓶颈。在宽泛的 CDS 视图中,情况往往并非如此:如果精确匹配 WHERE key = '…' 和 LIKE 一样慢,耗时来自视图的联接/DISTINCT/$count,而非通配符(第 2 级,“精确匹配也慢?”)。先测量两者,再判断是否是 LIKE 的问题。


输出

给出简明的诊断,而不是工具日志:

  1. 结论——DB/应用/框架/认证问题,并提供证据数值(例如,"gwappdb 为 412 ms,gwtotal 为 480 ms")。引用 SAP 数值(gwtotal/gwappdb),不要引用 wallClockMs:墙上时钟时间还包括网络/MCP/代理耗时(odata_perf 会通过 clientWaitMs 返回这部分差值),因此当 clientWaitMs 远大于 gwtotal 时,延迟来自整个系统环境,而非查询。
  2. 语句——问题 SQL(来自 cds_sql/ST05)以及它扫描的内容(SAPQuery totalRows/ST05 获取的行数、表、缺失的索引)。
  3. 根本原因——用一句话概述,并对应上述目录。
  4. 修复方案——具体且精简(要添加的索引、要下推的筛选条件、要合并的 N+1),优先选择成本最低的方案,并说明权衡。
  5. 证据——实际运行的 ARC-1 调用,以及任何 ST05/HANA 执行计划捕获结果,以便用户重新验证。

务必停用所有已启用的跟踪。在 PROD 上,优先使用只读信号(odata_perf、cds_sql、SAPQuery、只读跟踪),启用 ST05 跟踪或更改状态前,务必取得明确批准。

评论

支持 Markdown