数据库性能

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

#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 不能使用索引

相关笔记