先纠正一个常见误区:AWR 里的 SQL_EXECUTIONS 数值偏高,并不直接等同于业务调用量就很大。如果直接按该字段降序排列,最先出现的往往是心跳检测、日志写入、SELECT 1 FROM DUAL 这类基础设施类语句——这些如同噪音一般,将真实的业务热点完全淹没。要准确评估业务逻辑是否合理,关键并非统计“执行了多少次”,而是深入分析“为何会执行这么多次”。
首先过滤已知的低价值 SQL 语句
在 AWR 的高频 SQL 列表中,大量语句来自应用框架或中间件自动生成的“干扰噪音”。如果不将这些杂质先行剔除,后续的分析工作将徒劳无功。

- 借助
SQL_TEXTLIKE 匹配典型模式:'SELECT 1%'、'INSERT INTO LOG_%'、'UPDATE %_STATUS' - 排除
MODULE = 'JDBC Thin Client'且PROGRAM包含'ConnectionPool'或'HealthCheck'的记录 - 跳过
FORCE_MATCHING_SIGNATURE = 0的短 SQL(例如COMMIT、ROLLBACK),这类语句无法有效聚合,自身也不反映业务逻辑
利用 EXECUTIONS_DELTA 与 FORCE_MATCHING_SIGNATURE 对齐业务语义
SQL_ID 的粒度过于细致——MyBatis 拼接 IN 列表、JPA 动态 WHERE 条件时,即便查询的是同一张表与同一字段,SQL_ID 也会完全不同。真正能够代表“一个业务动作”的标识,实际上是 FORCE_MATCHING_SIGNATURE。
- 查询
DBA_HIST_SQLSTAT时必须GROUP BY FORCE_MATCHING_SIGNATURE,随后SUM(EXECUTIONS_DELTA)进行汇总 - JOIN
DBA_HIST_SQLTEXT获取任意一条代表性文本,通过人工方式识别业务意图(例如看到WHERE status = :1,即可判断这是“查询状态”的操作) - 若数据库未启用
cursor_sharing = FORCE,部分 SQL 签名为空,此时可退而采用正则提取:统一将以FROM orders WHERE user_id =开头的语句归类为“用户订单查询”
结合 ASH 定位真实的调用上下文
AWR 提供的是每小时一次的快照数据,根本无法捕捉“30 秒内执行了 70 次”这类瞬时高频行为——比如每秒查询 JUDGE_TASK WHERE STATUS='0' 的任务轮询。这种节奏型的执行模式,只有 DBA_HIST_ACTIVE_SESS_HISTORY 才能清晰呈现。
- 查询
SQL_ID对应的活跃会话,重点关注MODULE、ACTION、CLIENT_ID(如果应用层已设置相关参数) - 在时间维度上,使用
SAMPLE_TIME聚合分钟级别的执行频次,确认是否为固定周期触发(例如每 30 秒触发一次) - 如果
PLSQL_ENTRY_OBJECT_ID不为空,JOINDBA_OBJECTS即可直接定位到具体是哪个存储过程或程序包在驱动这条 SQL
执行频次异常的典型信号与判断方法
业务逻辑不合理的常见表现,往往是“单次业务请求引发 N 次相同 SQL 执行”,而非“N 次业务请求各自触发一次 SQL”。这类问题通过肉眼即可初步判断:
- 同一条 SQL 在 30 分钟内执行次数超过 10 万次,但对应业务表每天仅新增几十条数据(例如
JUDGE_TASK表仅有 60 行记录,却每天被查询 600 万次) EXECUTIONS_DELTA与ELAPSED_TIME_DELTA的比值极低(执行 10 万次总耗时仅需几秒),说明 SQL 本身非常轻量,高频执行的根源在于轮询或重试逻辑- 物理读与执行次数的比值正常(
PHYSICAL_READS / EXECUTIONS < 10),但逻辑读与执行次数的比值极高(>5000),这大概率是索引全扫描配合ROWNUM截断所致,未走最优执行路径
归根结底,真正的难点不在于统计执行次数,而在于将 EXECUTIONS_DELTA 准确映射回具体的业务动作。针对每一个 FORCE_MATCHING_SIGNATURE 对应的频次,都应该能够清晰说明:“这是用户下单时查询库存、这是定时任务清理归档数据、这是接口幂等性校验”。否则,数据再精准,也难以落地转化为有效的优化行动。
