Mark的技术博客

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)

吴让宇(Mark)

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)的个人技术博客,专注于SAP系统实施、行业方案咨询、IT技术与AI技术的研究与分享。

SAP Fiori ABAP CDS OData Dify Docker AI LLM

最新文章

数据库访问性能 (★★★)

#performance #open-sql #database

SELECT 优化规则

规则 反模式 最佳实践
指定列 SELECT * SELECT col1 col2 col3
使用 WHERE 全表扫描 WHERE indexed_col = value
数组读取 循环中 SELECT SINGLE SELECT ... INTO TABLE
限制行数 无行数限制 UP TO n ROWS
使用索引 未索引的 WHERE WHERE 使用索引字段

缓冲策略

何时缓冲 何时不缓冲
频繁读取的表 频繁更改的表
中小型表 非常大的表
读多写少的工作负载 写多读少的工作负载
相对静态的数据 实时数据需求
📌缓冲对读多改少的表有效。频繁更改的表导致持续的缓冲失效,抵消了缓冲的好处。

索引使用

索引如何工作

1
2
3
4
5
6
7
8
9
10
11
12
13
表:SFLIGHT
主索引: MANDT + CARRID + CONNID + FLDATE
次索引: MANDT + PLANETYPE

查询:SELECT ... WHERE carrid = 'LH' AND connid = '0400'
→ 使用主索引(最左前缀匹配)

查询:SELECT ... WHERE planetype = '747'
→ 使用次索引

查询:SELECT ... WHERE fldate = '20240101'
→ 无索引匹配(fldate 是主索引第4个字段,无左前缀)
→ 全表扫描!

索引使用规则

规则 详情
最左前缀 WHERE 必须从左到右包含索引的前导字段
不能跳过 不能跳过索引中间的字段
等值最优 = 条件使用索引最高效
范围降低效率 ><BETWEENLIKE 仍使用索引但效率较低
OR 中断 OR 条件可能阻止索引使用
否定中断 <>NOT IN 不能使用索引

数组读取 vs 单条记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
" 不好:循环中单条记录访问
LOOP AT lt_keys INTO ls_key.
SELECT SINGLE * FROM sflight INTO ls_flight
WHERE carrid = ls_key-carrid
AND connid = ls_key-connid.
APPEND ls_flight TO lt_result.
ENDLOOP.

" 好:数组读取
IF lt_keys IS NOT INITIAL.
SELECT * FROM sflight INTO TABLE lt_result
FOR ALL ENTRIES IN lt_keys
WHERE carrid = lt_keys-carrid
AND connid = lt_keys-connid.
ENDIF.

" 最好:JOIN(如果可能)
SELECT f~*
INTO TABLE lt_result
FROM sflight AS f
INNER JOIN some_table AS s
ON f~carrid = s~carrid.
方式 数据库往返 性能
循环中的 SELECT SINGLE n(很差) O(n) 次查询
FOR ALL ENTRIES 1(或少量) 良好
JOIN 1 最佳

FOR ALL ENTRIES 性能

考虑事项 详情
检查 IS NOT INITIAL 空表 = 全表扫描
精简驱动表 SORT + DELETE ADJACENT DUPLICATES
限制驱动表大小 大表分批处理
使用索引字段 WHERE 字段应匹配索引

嵌套 SELECT 反模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" 反模式:嵌套 SELECT
SELECT * FROM spfli INTO TABLE lt_routes.
LOOP AT lt_routes INTO ls_route.
SELECT * FROM sflight INTO TABLE lt_flights " 每条路线一次查询!
WHERE carrid = ls_route-carrid
AND connid = ls_route-connid.
" 处理
ENDLOOP.

" 正确:单次 JOIN
SELECT p~carrid, p~connid, p~cityfrom, f~fldate, f~price
INTO TABLE lt_result
FROM spfli AS p
INNER JOIN sflight AS f
ON p~carrid = f~carrid AND p~connid = f~connid.
循环中的 SELECT 是最常见的性能杀手。始终用 JOIN、FOR ALL ENTRIES 或预缓冲替换。

SQL 跟踪查找瓶颈

工具 事务 用途
SQL 跟踪 ST05 识别慢速 SQL 语句
运行时分析 SE30 整体性能分析
代码检查器 SCI 性能的静态代码分析
💡使用 SQL 跟踪(ST05)识别哪些 SQL 语句消耗最多时间。查找重复的 SELECT 和缺失的索引使用。

性能检查清单

1
2
3
4
5
6
7
8
9
10
11
12
+------------------------------------------+
| 数据库性能检查清单 |
+------------------------------------------+
| [ ] SELECT 仅指定需要的列 |
| [ ] WHERE 使用索引字段 |
| [ ] 循环中没有 SELECT |
| [ ] 使用 INTO TABLE 而非逐行处理 |
| [ ] FOR ALL ENTRIES:表不为空 |
| [ ] 静态表使用了缓冲 |
| [ ] 没有不必要的 ORDER BY / GROUP BY |
| [ ] 大结果集使用 PACKAGE SIZE |
+------------------------------------------+

考试/测试模式

关键词 / 短语 答案
“最重要的 SELECT 优化” 指定列(避免 SELECT *
“循环中 SELECT 的解决方案” 用 JOIN 或 FOR ALL ENTRIES 替换
“缓冲最适合” 频繁读取、很少更改的表
“索引最左前缀规则” WHERE 必须从左包含索引的前导字段
“FOR ALL ENTRIES 前提条件” 检查驱动表 IS NOT INITIAL
“数组读取的优势” 单次数据库往返 vs n 次往返
“SQL 跟踪事务” ST05
“精简 FOR ALL ENTRIES 表” SORT + DELETE ADJACENT DUPLICATES
“否定运算符和索引” <>NOT IN 不能使用索引

相关笔记

SQL 跟踪 (★★)

#debugging #analysis-tools #performance #open-sql

用途

方面 详情
事务 ST05
目标 跟踪和分析数据库执行的 SQL 语句
输出 所有 SQL 操作的详细列表及时间

SQL 跟踪操作

操作 含义
PREPARE 解析 SQL 语句并创建执行计划
OPEN / REOPEN 为 SELECT 打开游标(或用新参数重新打开)
FETCH 从游标获取行
EXEC / REEXEC 执行非 SELECT 语句(INSERT、UPDATE、DELETE)
1
2
3
4
执行流程:
PREPARE → OPEN → FETCH(重复) → (隐式关闭)
非 SELECT:
PREPARE → EXEC (或 REEXEC 重新执行)

跟踪过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+------------------+
| 1. 启动跟踪 | ← 激活跟踪(按用户/事务)
+--------+---------+
|
+--------v---------+
| 2. 执行工作 | ← 运行要跟踪的程序/事务
+--------+---------+
|
+--------v---------+
| 3. 停止跟踪 | ← 停用跟踪
+--------+---------+
|
+--------v---------+
| 4. 显示跟踪 | ← 分析跟踪列表
+------------------+

跟踪列表列

描述
Duration 执行时间(微秒)
Object name 数据库表名
Operation PREPARE、OPEN、FETCH、EXEC 等
Records 影响的行数
RC 返回代码(0 = 成功)
Statement 实际的 SQL 语句

EXPLAIN SQL

功能 详情
用途 显示数据库特定的访问策略
方法 选中一条语句 → EXPLAIN
显示 使用了哪个索引、访问路径、估计成本
1
2
3
4
5
EXPLAIN 输出(示例):
表: SFLIGHT
访问: INDEX RANGE SCAN
使用索引: SFLIGHT~01(主索引)
条件: MANDT='100' AND CARRID='LH'
💡对慢速 SELECT 使用 EXPLAIN 验证数据库优化器是否使用了预期的索引。全表扫描表示缺少或未使用的索引。

汇总跟踪结果

汇总类型 分组依据
按 SQL 语句 相同 SQL 文本
按相同访问 相同表 + 操作

识别优化潜力

1
2
3
4
5
6
7
8
9
10
11
跟踪显示:
SELECT * FROM SFLIGHT WHERE CARRID='LH' 耗时:120ms 记录:5
SELECT * FROM SFLIGHT WHERE CARRID='BA' 耗时:95ms 记录:3
SELECT * FROM SFLIGHT WHERE CARRID='AF' 耗时:110ms 记录:4
SELECT * FROM SFLIGHT WHERE CARRID='DL' 耗时:88ms 记录:2

按相同访问汇总:
SFLIGHT / SELECT / 4 次调用 / 总计:413ms / 平均:103ms

→ 优化:用单次 SELECT ... FOR ALL ENTRIES 替换
或 JOIN(4 次往返 → 1 次)
📌在跟踪中查找相同的 SELECT。多个相似 SELECT 表示循环中 SELECT 模式,应替换为 JOIN 或 FOR ALL ENTRIES。

跟踪配置

设置 详情
跟踪范围 所有用户、特定用户或事务
跟踪类型 SQL 跟踪、RFC 跟踪、入队跟踪、缓冲跟踪
文件大小 rstr/max_filesize_MB 配置参数控制最大跟踪文件大小
持续时间 保持跟踪简短;大型跟踪影响性能
⚠️SQL 跟踪增加开销。仅跟踪你想分析的特定操作,然后立即停止跟踪。

跟踪分析工作流

1
2
3
4
5
1. 按耗时排序(降序)         → 找到最慢的语句
2. 按记录数排序(降序) → 找到最大的结果集
3. 按相同访问汇总 → 找到重复的相同查询
4. 对慢速语句使用 EXPLAIN → 验证索引使用
5. 修复问题并重新跟踪 → 测量改进

考试/测试模式

关键词 / 短语 答案
“SQL 跟踪事务” ST05
“PREPARE 操作” 解析 SQL 语句,创建执行计划
“FETCH 操作” 从打开的游标获取行
“EXEC 操作” 执行非 SELECT 语句(INSERT/UPDATE/DELETE)
“EXPLAIN SQL 显示” 数据库访问策略(使用的索引、访问路径)
“按相同访问汇总” 按相同表+操作分组以查找重复查询
“相同 SELECT 表示” 循环中 SELECT 模式;使用 JOIN 或 FOR ALL ENTRIES
“跟踪文件大小参数” rstr/max_filesize_MB
“跟踪开销警告” SQL 跟踪增加开销;仅跟踪需要的

相关笔记

ABAP 工具练习 (8题)

#practice #debugging #analysis-tools

相关概念

📌核心模式(点击查看)
关键词 答案
新调试器关键点 在独立的外部会话中运行
观察点 字段内容改变时触发
运行时分析 SAT/SE30,Aggregation=None 获取详情
代码检查器 SCI,检查变体 + 对象集
SQL 跟踪 EXPLAIN 显示访问策略和使用的索引

第1题 - 新调试器优势 [记忆]

说出新版调试器相比传统调试器的三个优势。

📌点击查看答案
  1. 独立的外部会话 – 不干扰应用程序滚动区
  2. 自由可配置的 UI – 最多 9 个可自定义桌面
  3. 设置跨会话保留
  4. 可以调试转换出口和字段出口(旧调试器不支持)

第2题 - 观察点 [记忆]

观察点与断点有何不同?

📌点击查看答案
方面 断点 观察点
触发条件 到达特定代码行时 字段内容改变
定义位置 代码中或调试器中 仅在调试器中
数量限制 无固定限制 最多 10 个观察点
链接 不适用 可用 AND/OR 运算符链接

观察点监控字段值,仅在值实际改变时激活调试。


第3题 - 调试器内存分析 [应用]

怀疑程序内表使用了过多内存。如何在调试器中分析?

📌点击查看答案
在调试器中使用菜单路径 转到 → 状态显示 → 内存使用
  • 内存使用 – 总计:整体内存消耗
  • 内存使用 – 排序列表:按占用内存排序的数据对象
  • 内存使用 – SCC:动态对象(内表、字符串、对象实例)

对于更深入的分析,保存内存提取并使用内存检查器(事务 S_MEMORY_INSPECTOR)分析。


第4题 - 运行时分析测量 [记忆]

运行时分析工具中运行时测量的三个区域是什么?

📌点击查看答案
区域 测量内容
ABAP 所有 ABAP 语句执行时间(不包括数据库)
数据库 所有数据库访问时间
系统 程序加载过程、生成、其他系统活动

第5题 - 运行时分析变体 [应用]

详细运行时分析推荐什么变体设置?为什么?

📌点击查看答案
设置 Aggregation = None。这提供未聚合的测量结果,按单个调用进行详细分组。聚合结果隐藏了具体的调用层次,使得精确定位瓶颈更困难。

创建自己的变体(而非 DEFAULT)并使用此设置,可选地将测量限制到特定的程序操作以减少噪音。


第6题 - 代码检查器工作流 [记忆]

描述运行代码检查器检查任务所需的三个组件。

📌点击查看答案
  1. 检查变体:定义执行哪些检查(性能、安全、语法、规范)
  2. 对象集:定义检查哪些对象(特定程序、包或对象列表)
  3. 检查任务:将检查变体与对象集组合。命名以持久化;未命名的检查任务不被保存。

第7题 - SQL 跟踪 EXPLAIN [应用]

对一个慢速 SELECT 运行 SQL 跟踪,发现它使用全表扫描。如何使用 EXPLAIN 诊断和修复?

📌点击查看答案
  1. 在跟踪列表中,将光标定位到 PREPAREOPEN 操作上
  2. 点击 Explain SQL(或跟踪列表 → SQL 跟踪 → Explain SQL)
  3. EXPLAIN 输出显示访问策略使用的索引
  4. 如果没有使用索引(全表扫描),检查:
    • WHERE 子句字段是否匹配现有索引
    • 是否需要创建适当的次索引
  5. 创建/调整索引后,重新跟踪验证改进

第8题 - SQL 跟踪相同 SELECT [分析]

在 SQL 跟踪中,发现某个 SELECT 的 75% 执行是相同的(相同 SQL、相同绑定变量值)。这提示什么优化?

📌点击查看答案
这表示通过数据缓冲75% 的优化潜力。相同 SQL 以相同绑定变量执行返回相同结果,因此冗余的 75% 可以通过以下方式消除:
  1. 应用级缓冲:一次读取到内表,然后在内存中查找
  2. SAP 表缓冲:如果表适合,在 ABAP 字典中启用缓冲

SQL 跟踪的”显示相同 SELECT”功能准确显示有多少执行是冗余的,并计算优化潜力百分比。


📌模式总结(点击查看)
关键词 答案
新调试器会话 独立的外部会话
观察点触发 字段内容改变时
内存分析 转到 → 状态显示 → 内存使用
运行时区域 ABAP、数据库、系统
Aggregation = None 详细的、非聚合结果
SCI 组件 检查变体 + 对象集 = 检查任务
EXPLAIN SQL 显示访问策略 + 索引使用
相同 SELECT 缓冲数据以避免冗余读取

检查点与断言 (★★)

#testing #abap-basics

三种检查点类型

类型 语句 无条件? 效果
断点 BREAK-POINT 是(不带 ID) 启动调试器
断言 ASSERT 有条件 条件为假时产生转储
日志点 LOG-POINT 需要 ID 记录到检查点组

BREAK-POINT 语句

1
2
3
4
5
6
7
8
" 无条件 - 始终激活,启动调试器
BREAK-POINT.

" 用户特定 - 仅对指定用户
BREAK username.

" 带检查点组 - 可通过 SAAB 激活
BREAK-POINT ID zcg_debug.
形式 激活时机 可传输?
BREAK-POINT 始终 在生产中危险
BREAK username 仅对用户 username 更安全
BREAK-POINT ID group 当组在 SAAB 中激活时 安全(可停用)
BREAK-POINT 不带 ID 始终激活。传输到生产环境前必须移除。改用 BREAK-POINT ID group

ASSERT 语句

1
2
3
4
5
6
7
8
" 简单断言
ASSERT sy-subrc = 0.

" 带检查点组(可激活)
ASSERT ID zcg_check CONDITION sy-subrc = 0.

" 带 FIELDS(失败时记录额外数据)
ASSERT ID zcg_check FIELDS lv_value lt_data CONDITION lv_value > 0.
部分 用途
CONDITION 要检查的布尔表达式
FIELDS obj1 obj2 ... 失败时记录的数据对象
ID group 用于激活控制的检查点组
💡ASSERT 比等效的 IF ... ENDIF 加错误处理更简短、更易读。它直接表达意图:”此条件必须成立。”

ASSERT vs 基于 IF 的检查

1
2
3
4
5
6
7
" 基于 IF(冗长)
IF sy-subrc <> 0.
MESSAGE 'Unexpected error' TYPE 'X'. " 或 RAISE EXCEPTION
ENDIF.

" ASSERT(简洁)
ASSERT sy-subrc = 0.

LOG-POINT 语句

1
2
3
4
5
" 基本日志点
LOG-POINT ID zcg_log.

" 带 FIELDS 记录数据
LOG-POINT ID zcg_log FIELDS lv_status lt_keys.
规则 详情
必须有 ID 日志点要求检查点组
CONDITION 日志点是无条件的(激活时)
记录到 事务 SAAB 日志
📌LOG-POINT 始终需要 ID group。与断点不同,日志点不能在没有检查点组的情况下使用。

检查点组(事务 SAAB)

检查点组集中控制所有三种检查点类型的激活。

激活状态

检查点类型 不活跃 中断 日志 中止
断点 无效果 调试器启动 记录 不适用
断言 无效果 调试器启动 记录 短转储
日志点 无效果 不适用 记录 不适用
1
2
3
4
5
6
SAAB 激活:
+----------+ +---------+ +-------+
| 不活跃 | | 中断 | | 日志 | +-------+
| (默认) | | 调试器 | | 写入 | | 中止 |
+----------+ +---------+ +-------+ | 转储 |
+-------+

SAAB 配置

设置 选项
有效性 所有用户、特定用户或外部断点
激活 临时(直到注销)或持久
范围 整个组或特定检查点
💡使用检查点组将断言和日志点保留在生产代码中。仅在调试生产环境问题时激活它们。

断言 vs 异常

方面 断言 异常
用途 验证不变量 / 开发者假设 处理预期的错误条件
受众 开发者(在生产中不应失败) 终端用户 / 调用代码
使用时机 前置条件、后置条件、不变量 业务逻辑错误、资源问题
生产环境 可通过 SAAB 停用 始终激活
📌断言和异常是互补的,不是替代关系。断言用于”这不应该发生”的检查,异常用于”这可能发生”的错误。

最佳实践

实践 原因
使用检查点组(SAAB) 集中激活控制
传输前移除静态 BREAK-POINT 防止生产环境调试器
在代码中保留 ASSERT ID group 可为生产调试激活
使用 LOG-POINT 进行跟踪 比断点更轻量,不中断
FIELDS 附加项用于诊断 失败时查看相关数据

考试/测试模式

关键词 / 短语 答案
“LOG-POINT 需要什么?” 必须有 ID group(检查点组)
“ASSERT 条件为假时” 短转储(或根据 SAAB 状态中断/记录)
“SAAB 断言状态” 不活跃、中断、记录、中止
“SAAB 日志点状态” 不活跃、记录
“BREAK-POINT 不带 ID 在生产环境” 始终激活 – 传输前必须移除
“FIELDS 附加项用途” 检查点触发时记录数据对象内容
“断言 vs 异常” 互补:断言 = 不变量,异常 = 预期错误
“断言激活控制” 通过检查点组(事务 SAAB)

相关笔记

检查点练习 (8题)

#practice #testing #debugging

相关概念

📌核心模式(点击查看)
关键词 答案
BREAK-POINT 无条件,启动调试器
ASSERT 有条件,条件为假时转储
LOG-POINT 仅记录,必须有 ID
检查点组 SAAB 事务,激活/停用
断言状态 不活跃、中断、记录、中止

第1题 - 检查点类型 [记忆]

说出三种检查点类型及其主要特征。

📌点击查看答案
类型 语句 激活时的效果
断点 BREAK-POINT [ID grp] 中断程序,启动调试器
断言 ASSERT [ID grp] condition 条件为假时:根据组设置转储/中断/记录
日志点 LOG-POINT ID grp [FIELDS ...] 写入检查点组日志;从不中断

第2题 - ASSERT 语法 [记忆]

ASSERT 条件评估为假且没有分配检查点组时会发生什么?

📌点击查看答案
没有检查点组(ASSERT condition)时,断言始终激活且无条件的。如果条件为假,立即产生运行时错误(转储) – 程序以 ASSERTION_FAILED 短转储终止。

第3题 - 检查点组 [记忆]

如何创建和配置检查点组?

📌点击查看答案
  1. 在对象导航器或事务 SAAB 中创建
  2. 输入名称(必须在客户命名空间中,如 ZBC402_##
  3. 添加描述性短文本
  4. 保存
  5. 为每种检查点类型配置激活状态:
    • 断言:不活跃 / 中断 / 记录 / 中止
    • 断点:不活跃 / 中断
    • 日志点:不活跃 / 记录

第4题 - 断言 vs 异常 [分析]

何时应使用 ASSERT,何时应抛出异常?

📌点击查看答案
方面 ASSERT 异常
用途 验证关于程序状态的假设 处理意外但可能的情况
激活时机 开发/测试(可在生产中停用) 始终激活
恢复 无恢复(转储/中断) 可被捕获和处理
使用场景 “这不应该发生” “这可能发生,需要处理”

断言验证内部正确性(如私有方法中的参数验证)。异常处理运行时条件(如文件未找到、数据库错误)。


第5题 - 静态 vs 可激活断点 [应用]

在生产代码中使用 BREAK-POINT(不带 ID)有什么风险?如何预防?

📌点击查看答案
BREAK-POINT 不带 ID 始终激活 – 它会中断在生产环境中执行程序的任何用户,造成干扰。预防方法:
  1. 改用 BREAK-POINT ID checkpoint_group(可停用)
  2. 传输前运行扩展程序检查 – 它将静态断点标记为错误
  3. 发布传输前始终移除 BREAK-POINTBREAK username 语句

第6题 - LOG-POINT 要求 [记忆]

LOG-POINT 有什么是其他检查点类型可选的强制性要求?

📌点击查看答案
LOG-POINT 必须始终ID group 附加项。与断点和断言不同,日志点不能在没有检查点组的情况下使用。因为日志点没有独立行为 – 它们仅在检查点组激活时产生输出。

第7题 - FIELDS 附加项 [应用]

你想在日志点到达时记录 lv_flight_date 的值。写出语句。

📌点击查看答案
1
LOG-POINT ID zbc402_check FIELDS lv_flight_date.

FIELDS 附加项将指定数据对象的内容存储在检查点组的日志中。最多可指定 8 个数据对象。引用变量不能被记录。


第8题 - 方法设计中的断言 [分析]

一个方法 find_item 接收一个键参数并从内表中读取。设计两个断言:一个在入口,一个在出口。

📌点击查看答案
1
2
3
4
5
6
7
8
9
METHOD find_item.
" 入口断言:验证键在有效范围内
ASSERT item_key >= 1 AND item_key <= LINES( item_table ).

READ TABLE item_table INTO result WITH KEY table_key = item_key.

" 出口断言:验证找到了结果
ASSERT result IS NOT INITIAL.
ENDMETHOD.

入口断言验证调用者的输入。出口断言验证方法自身的结果。两者共同确保方法的契约被满足。


📌模式总结(点击查看)
关键词 答案
BREAK-POINT 无条件启动调试器
ASSERT 条件为假 无组时转储;有组时可配置
LOG-POINT 必须有 ID,从不中断
SAAB 检查点组维护事务
断言状态 不活跃/中断/记录/中止
FIELDS 记录数据对象(最多8个,不含引用)
断言 vs 异常 验证假设 vs 处理意外

BC430 — ABAP 字典考试陷阱

#dashboard #abap #abap-dictionary #exam-traps

⚠️此笔记目的
汇总 BC430 考试中容易出错的陷阱和常见混淆点。

Unit 1: 字典概述

Trap: 域不能直接在程序中使用
  • 域定义技术属性,但 ABAP 程序不能直接引用域
  • 必须通过数据元素作为桥梁 → 程序中 TYPE data_element
  • 域与数据元素

Unit 2: 数据对象

Trap: LCHR 长度限制
  • CHAR 在表中最大 255 字符,超过必须用 LCHR
  • 但结构中 CHAR 无长度限制
  • 域与数据元素
Trap: 深层结构与数据库表
  • 深层结构(含内表组件)可以定义和使用
  • 但数据库表只能包含扁平结构
  • 结构与表类型
Trap: Include 结构 vs 嵌套结构
  • Include (.INCLUDE): 字段直接展开到父结构中,不增加嵌套层级
  • 嵌套: 通过组件名引用子结构,增加层级(wa-name-firstname
  • 混淆两者是常见错误
  • 结构与表类型
Trap: Include 链中的数据库表
  • 一个 Include 链中只能包含一个数据库表(就是被 Include 的表本身)
  • 不能将一个透明表 Include 到另一个透明表中
  • 透明表与Include结构
Trap: 池表键字段类型
Trap: 日志需要两个条件
  • 技术设置中勾选日志 不够
  • 还需要 profile 参数 rec/client 设置为 ALL 或具体客户端号
  • 技术设置与日志

Unit 3: 性能

Trap: 索引使用顺序
  • 索引只能使用到最后一个在 WHERE 中指定的字段
  • 跳过中间字段会导致后续字段无法使用索引
  • 索引与表缓冲
Trap: 缓冲同步延迟
  • 缓冲数据在同步前可能有延迟
  • /$TAB 重置缓冲会严重影响性能(大型系统需数小时重新填充)
  • 索引与表缓冲

Unit 4: 输入检查

Trap: 外键基数第一个数字
  • 基数格式 N:M — 第一个数字始终为 1(一条检表记录对应)
  • 第二个数字: 1/C/N/CN(对应外键表中的记录数)
  • 外键与一致性检查
Trap: 文本表的特殊外键
  • 文本表的 Language 字段必须用域 SPRAS
  • 检表为 T002(语言表)
  • 文本表与主表是 1:N 关系(不是 N:1)
  • 文本表

Unit 5: 对象依赖

Trap: 运行时对象不一致
  • 运行时对象(DD02L 等)必须与数据库结构一致
  • 修改后不激活 → 运行时错误
  • 对象依赖关系

Unit 6: 表变更

Trap: 缩短键字段导致数据丢失
  • 转换时用 MOVE-CORRESPONDING 回填
  • 键字段缩短后,无法区分的记录只保留一条(随机选择)
  • 必须在转换前清理数据
  • 表转换过程
Trap: 转换期间表不可用
  • 转换过程中表名变为 QCM 前缀
  • 原表名不存在,所有访问该表的程序无法运行
  • 转换不能在生产时间执行
  • 表转换过程
Trap: 终止转换不能简单解锁
  • 转换终止在 Step 3/4 时,数据仅在临时表中
  • 绝不能选 “Unlock table” — 会丢失数据
  • 必须选 “Continue adjustment” 继续
  • 表转换过程
Trap: Append 结构字段命名
Trap: 增强类别与 Unicode
  • 纯字符型结构增强后可能失去字符特性
  • 影响赋值检查、偏移量访问等
  • Unicode 环境下更严格
  • Append结构与表增强

Unit 7: 视图

Trap: 内连接 vs 外连接
  • 数据库视图 = 内连接(Inner Join): 只返回所有表都有匹配的记录
  • 维护视图 = 外连接(Outer Join): 也返回无匹配的记录
  • 数据库视图
Trap: 数据库视图可写条件
  • 多表数据库视图只能读
  • 单表数据库视图才能写
  • 数据库视图

Unit 8: 搜索帮助

Trap: IMPORT 参数 vs 搜索字段
  • 搜索字段的内容仅在包含通配符 ( 或 +) 时*才传递给 IMPORT 参数
  • 否则搜索字段值被忽略
  • 仅显示信息的参数不应设为 IMPORT(否则用户需清空才能新搜索)
  • 搜索帮助基础
Trap: 维护视图不能作选择方法
  • 搜索帮助的选择方法不能用维护视图
  • 应使用数据库视图或 Help 视图
  • 搜索帮助基础
Trap: 搜索帮助挂接优先级
  • 最高优先级:结构/表字段上的直接挂接
  • 中间:检表上的搜索帮助
  • 最低:数据元素上的搜索帮助 → 域固定值
  • 同一字段多个机制时,选最高优先级
  • 搜索帮助挂接

  • [[学习地图-BC430]] → 弱项区域
  • [[快速参考-BC430]]

运行时分析 (★★)

#debugging #analysis-tools #performance

用途

方面 详情
事务 SE30(或 SAT 新版本)
目标 测量运行时需求,定位性能瓶颈
测量内容 ABAP、数据库和系统层花费的时间

测量过程

1
2
3
4
5
6
7
8
9
10
11
+------------------+
| 1. 定义变体 | ← 选择测量什么和如何测量
+--------+---------+
|
+--------v---------+
| 2. 执行 | ← 运行程序/事务
+--------+---------+
|
+--------v---------+
| 3. 分析 | ← 查看命中列表和调用层次
+------------------+

测量类别

类别 测量内容
ABAP ABAP 处理时间(语句、模块化单元)
数据库 数据库操作时间(SQL 语句)
系统 系统调用时间(I/O、滚动区等)
💡进行详细分析时,设置 Aggregation = None。这显示每个单独的调用而非汇总的合计。

聚合级别

聚合 详细程度 使用场景
None 每次单独调用 详细分析(推荐)
按调用位置 按调用位置汇总 识别热点
按调用者 按调用程序汇总 程序级概览
📌聚合 = None 是详细分析的推荐设置。其他聚合级别隐藏单个调用信息。

命中列表

命中列表 显示内容
分组命中列表 每个模块化单元的时间(方法、FORM、函数)
内表命中列表 内表操作花费的时间
数据库表命中列表 每个数据库表访问花费的时间
1
2
3
4
5
6
7
8
分组命中列表(示例):
+-----------------------------+----------+--------+
| 模块化单元 | 总时间 % | 净时间 % |
+-----------------------------+----------+--------+
| ZCL_ORDER=>PROCESS | 45.2 | 2.1 | ← 调用其他单元
| ZCL_ORDER=>READ_DATA | 38.1 | 38.1 | ← 自包含
| ZCL_ORDER=>CALCULATE | 15.0 | 15.0 | ← 自包含
+-----------------------------+----------+--------+

总时间 vs 净时间

指标 含义
总时间(Gross) 包括所有被调用子程序的总时间
净时间(Net) 单元本身花费的时间(不包括被调用单元)
1
2
3
4
5
6
Process(总:45s,净:2s)
├── Read_Data(总:38s,净:38s) ← 真正的瓶颈
└── Calculate(总:15s,净:15s)

总时间 = 自身时间 + 所有被调用单元的时间
净时间 = 仅自身时间(不包括调用)
💡专注于净时间来找到实际的瓶颈。高总时间加低净时间意味着该单元调用了其他慢速单元。

技巧与提示

功能 用途
Tips & Tricks 按钮 通过测量的性能比较不同编码方法
比较 并排运行时比较两种实现
示例 预制示例展示慢速 vs 快速模式
💡Tips & Tricks 部分提供现成的性能比较,通过实际测量演示最佳实践。

考试/测试模式

关键词 / 短语 答案
“运行时分析事务” SE30(或 SAT)
“三个测量类别” ABAP、数据库、系统
“推荐的聚合级别” None(用于详细分析)
“总时间 vs 净时间” 总时间 = 包括子调用;净时间 = 仅自身时间
“分组命中列表显示” 每个模块化单元的时间
“内表命中列表显示” 内表操作花费的时间
“Tips & Tricks 用途” 不同编码方法的性能比较
“如何找到瓶颈” 在命中列表中查找最高净时间

相关笔记

BC430 — ABAP 字典快速参考

#dashboard #abap #abap-dictionary

核心数据类型层次 → 域与数据元素

Type (类型) Description (描述) Key Point (要点)
Domain (域) 技术属性(数据类型、长度、值域) 不能直接在程序中使用
Data Element (数据元素) 语义属性(字段标签、F1 帮助) 连接域与数据对象的桥梁
Structure (结构) 组件集合(扁平/嵌套/深层) 一维数据对象
Table Type (表类型) 内表描述(行类型+访问方式) 二维数据对象
Type Group (类型组) 全局常量定义 旧技术,名称最多 5 字符

常用域数据类型

Type Description Max Length
CHAR 字符串 表中 255,结构无限制
DATS 日期 固定 8
DEC 金额/计算字段 最多 31
NUMC 数字字符串 最多 255
CURR 货币字段 需要引用表
QUAN 数量字段 需要引用表+单位字段

表类型对比 → 特殊SAP表-池表与簇表

Feature Transparent (透明表) Pooled (池表) Cluster (簇表)
DB 中独立存在 否(合并到表池) 否(合并到表簇)
数据压缩
可建索引 仅键字段 仅簇键
JOIN / View 支持 不支持 不支持
Native SQL 可用 仅 Open SQL 仅 Open SQL

技术设置 → 技术设置与日志

Setting Options 说明
Data Class APPL0 / APPL1 / APPL2 / USER 主数据/事务数据/组织数据/客户
Size Category 0-4 控制扩展大小
Buffering 不允许/完全/通用/单记录 影响读性能
Logging 开/关 需配合 rec/client 参数

缓冲类型 → 索引与表缓冲

Type Trigger (触发) Loaded (加载) 适用场景
Full (完全) 访问任一记录 全表 小表、读频繁
Generic (通用) 访问某记录 同左键前缀的所有记录 按键前缀分组访问
Single (单记录) 访问某记录 仅该记录 大表、随机访问

外键基数 → 外键与一致性检查

Cardinality Meaning 示例
1:1 每个检表条目必须对应一条 必选且唯一
1:C 每个检表条目对应 0 或 1 条 可选
1:N 每个检表条目对应多条 一对多(必须)
1:CN 每个检表条目对应 0 或多条 一对多(可选)

外键字段类型

Type Description
Key fields/candidates 外键字段是检表键字段
Non-key fields/candidates 外键字段不是键字段
Key fields of a text table 文本表专用

视图类型对比 → 数据库视图维护视图与视图集群

Feature Database View Maintenance View Help View
Join Type Inner Join Outer Join Outer Join
可写 仅单表时可写 可读写 不可
缓冲 支持 不支持 不支持
用途 数据选择 数据维护 搜索帮助选表
外键要求 必须 必须

搜索帮助挂接优先级 → 搜索帮助挂接

  1. 屏幕字段直接挂接(Screen Painter)
  2. 结构/表字段上的搜索帮助
  3. 检表上的搜索帮助
  4. 数据元素上的搜索帮助
  5. 域固定值
  6. 时间相关检查表

表转换流程 → 表转换过程

1
2
3
4
5
6
7
Step 1: 锁定表 → 禁用视图
Step 2: 重命名原表为 QCMTAB(删索引)
Step 3: 用新结构创建 QCM8TAB
Step 4: MOVE-CORRESPONDING 回填数据(每 16MB commit)
Step 5: 删除 QCMTAB
Step 6: QCM8TAB → TAB(重建索引+视图)
Step 7: 释放锁

Append 结构规则 → Append结构与表增强

  • 字段名以 YYZZ 开头
  • 不能用于池表/簇表
  • 含 LCHR/LRAW 的表不能使用
  • 不需要表转换(ALTER TABLE)

关键事务码

T-Code Description
SE11 ABAP 字典维护
SE14 数据库工具(转换/修复)
SE54 表维护视图生成器
SM30 表维护(已生成视图)
SM34 视图集群维护
SCU3 表历史日志查看
  • [[学习地图-BC430]]
  • [[考试陷阱-BC430]]

ABAP 调试器 (★★)

#debugging #analysis-tools

旧版 vs 新版调试器

特性 旧版调试器 新版调试器
架构 在同一会话中运行 独立的外部会话中运行
UI 固定布局 自由可配置,最多 9 个桌面
设置 不保留 跨会话保留
调试中调试 不可能 可能(调试器可被调试)
可用性 遗留 NW 7.0 EhP1 起默认
💡新版调试器在独立的外部会话中运行,这意味着它不阻塞主会话的内存且可独立配置。

启动调试器

方法 操作
命令字段 输入 /H 并按回车
程序上下文菜单 右键 → 创建断点
系统菜单 系统 → 实用程序 → 调试 ABAP
在代码中 BREAK-POINTBREAK username
从 ABAP 编辑器 设置断点(外部或会话)

断点

类型

类型 描述 持久性
静态 硬编码的 BREAK-POINTBREAK user 在源代码中
动态 通过调试器 UI 设置 仅当前会话
语句 在特定 ABAP 语句处中断 仅当前会话
函数模块 FM 被调用时中断 仅当前会话
方法 方法被调用时中断 仅当前会话
异常 异常被抛出时中断 仅当前会话
系统断点 通过 SAAB 设置(事务级别) 通过检查点组

断点管理

1
2
3
4
调试器 → 断点选项卡
+ 创建:语句、函数、方法、异常
+ 删除单个或全部
+ 激活 / 停用
📌动态断点(在调试器中设置)仅存在于当前会话。静态断点(在代码中)持久存在但传输前必须移除。

观察点

特性 详情
用途 当字段内容改变时中断
最大数量 最多同时 10 个观察点
链接 多个观察点之间 AND / OR
范围 可限制到特定程序或 FORM
触发 当被观察的字段值改变时
1
2
3
4
观察点配置:
变量: lv_status
程序: ZMY_PROGRAM " 可选范围
条件: lv_status = 'X' " 可选条件
💡观察点在你不知道字段在哪里被更改,只需要找到更改点时很有用。

调试器桌面

桌面 内容
桌面 1(默认) 变量、源代码
桌面 2-9 用户可配置
可用工具 变量显示、表显示、对象显示、内存分析

可用工具

工具 用途
变量 显示局部/全局变量
结构 展开和导航结构
内表 浏览表内容
对象 检查对象属性
内存 分析内存消耗

内存使用显示

视图 描述
总计 程序使用的总内存
排序列表 按大小排序的内存消耗者
SCC(共享对象更改区) 共享内存使用
💡使用内存显示来识别调试期间哪些内表或对象消耗最多内存。

考试/测试模式

关键词 / 短语 答案
“新调试器架构” 在独立的外部会话中运行
“最大观察点数” 10 个(支持 AND/OR 链接)
“观察点触发条件” 字段内容改变
“动态 vs 静态断点” 动态 = 仅会话内;静态 = 在源代码中
“从命令字段启动调试器” 输入 /H 并按回车
“调试器桌面最大数” 9 个(自由可配置)
“内存显示视图” 总计、排序列表、SCC
“新旧调试器关键区别” 新版在独立的外部会话中运行

相关笔记

BC430 — ABAP 字典学习地图

#dashboard #abap #abap-dictionary

概述

  • SAP BC430 认证课程:ABAP Dictionary(ABAP 字典)
  • 涵盖 ABAP 字典对象定义、数据库表管理、性能优化等 8 个单元
  • 时长:3 天,SAP NetWeaver AS-ABAP 平台
  • 前置课程:BC400 或同等 ABAP 基础知识

主题地图

Section (单元) Source (来源) Notes (笔记) Status (状态)
Unit 1: 字典概述 Unit 1 (pp. 1-8) ABAP字典功能概述 [ ]
Unit 2: 数据对象 Unit 2 (pp. 9-74) 域与数据元素, 结构与表类型, 透明表与Include结构, 技术设置与日志, 特殊SAP表-池表与簇表 [ ]
Unit 3: 表访问性能 Unit 3 (pp. 75-100) 索引与表缓冲 [ ]
Unit 4: 输入检查 Unit 4 (pp. 101-130) 域固定值检查, 外键与一致性检查, 文本表 [ ]
Unit 5: 对象依赖 Unit 5 (pp. 131-146) 对象依赖关系 [ ]
Unit 6: 表变更 Unit 6 (pp. 147-174) 表转换过程, Append结构与表增强 [ ]
Unit 7: 视图与维护视图 Unit 7 (pp. 175-210) 数据库视图, 维护视图与视图集群 [ ]
Unit 8: 搜索帮助 Unit 8 (pp. 211-228) 搜索帮助基础, 集合搜索帮助与扩展, 搜索帮助挂接 [ ]

练习笔记

Question Set (题集) Questions (题数) Link (链接)
字典概述 8 单元1练习-字典概述
数据对象(域/数据元素/结构/表类型) 10 单元2练习-数据对象
透明表与技术设置 8 单元2练习-透明表
表访问性能 8 单元3练习-性能
输入检查与外键 10 单元4练习-输入检查
对象依赖 6 单元5练习-对象依赖
表变更与转换 10 单元6练习-表变更
视图 8 单元7练习-视图
搜索帮助 10 单元8练习-搜索帮助

学习工具

Tool (工具) Description (描述) Link (链接)
考试陷阱 常见错误和易错点 [[考试陷阱-BC430]]
快速参考 完整速查表 [[快速参考-BC430]]

标签索引

Tag (标签) Topics (主题) Hierarchy (层级)
#abap 顶级领域 Domain
#abap-dictionary ABAP 字典 abap > dictionary
#abap-data-types 数据类型(域/数据元素/结构) abap > dictionary > data-types
#abap-tables 数据库表 abap > dictionary > tables
#abap-performance 性能(索引/缓冲) abap > dictionary > performance
#abap-validation 输入检查(外键/固定值) abap > dictionary > validation
#abap-views 视图 abap > dictionary > views
#abap-search-help 搜索帮助 abap > dictionary > search-help

标签规则: 所有标签小写英文、kebab-case。Detail 标签必须附带父级 domain 标签。

弱项区域

非核心主题策略

Source (来源) Content (内容) Handling (处理)
Appendix Help Views 附录内容 简化提及 — 仅在搜索帮助选表时引用
0%