AWR中SQL_EXECUTIONS高不直接反映业务调用多,因其统计Oracle执行次数而非业务请求次数;需结合FORCE_MATCHING_SIGNATURE聚合语义相同SQL、过滤低价值SQL、利用ASH分析MODULE/ACTION上下文及PLSQL_ENTRY_OBJECT_ID定位真实业务频次。
AWR里SQL_EXECUTIONS高不等于业务调用多
awr视图中dba_hist_sqlstat.sql_executions统计的是该sql在采样周期内被oracle执行的总次数,但一次业务请求可能触发同一条sql执行多次(比如循环分页、批量插入、游标重复打开),也可能被硬解析/软解析多次计入不同sql_id。所以直接按sql_executions倒序排,常会把select 1 from dual、连接池心跳sql、日志表insert这类“基础设施sql”顶到前列,反而掩盖真实业务热点。
实操建议:
- 先过滤掉已知低价值SQL:用
SQL_TEXTLIKE匹配'SELECT 1%'、'INSERT INTO LOG_%'、'UPDATE %_STATUS'等模式,或排除MODULE为'JDBC Thin Client'且PROGRAM含'ConnectionPool'的记录 - 结合
EXECUTIONS_DELTA(非累计值)计算单位时间执行频次,避免长周期AWR快照拉高绝对值 - 优先看
DBA_HIST_SQLSTAT中FORCE_MATCHING_SIGNATURE相同的SQL组——它能把字面不同但语义一致的SQL(如IN列表长度不同、字面量替换)聚合成一个逻辑SQL,更贴近业务调用视角
用FORCE_MATCHING_SIGNATURE对齐业务语义
Oracle默认按SQL_ID区分SQL,但应用层用MyBatis动态拼IN、Spring Data JPA自动生成WHERE条件时,哪怕查同一张表同一字段,SQL_ID也完全不同。这时候FORCE_MATCHING_SIGNATURE才是关键——它忽略字面量,只保留结构特征,同一类业务操作(如“查用户订单列表”)大概率共享同一个签名。
实操建议:
- 查
DBA_HIST_SQLSTAT时GROUP BYFORCE_MATCHING_SIGNATURE,SUM(EXECUTIONS_DELTA),再JOINDBA_HIST_SQLTEXT取任一代表性SQL文本 - 注意
FORCE_MATCHING_SIGNATURE = 0的SQL要单独处理(通常是含绑定变量但未启用force matching,或SQL太短如COMMIT),不能直接丢弃 - 如果数据库未开启
cursor_sharing = FORCE,部分SQL可能无法生成有效签名,需回退到人工归类SQL_TEXT正则模式(如提取FROM orders WHERE status = :1统一标记为“订单状态查询”)
DBA_HIST_ACTIVE_SESS_HISTORY比AWR更能反映真实调用链
AWR是聚合快照,丢失了SQL执行的时间分布和上下文;而DBA_HIST_ACTIVE_SESS_HISTORY每秒采样一次活跃会话,带SQL_ID、SESSION_ID、MODULE、ACTION、甚至CLIENT_ID(如果应用设置了)。它能告诉你“哪个模块在什么时间段密集调用了哪条SQL”,这才是业务频次的原始证据。
实操建议:
- 按
MODULE+ACTION分组统计SQL_ID出现次数:COUNT(*) OVER (PARTITION BY MODULE, ACTION, SQL_ID),再排序 - 用
SESSION_ID和SQL_EXEC_START识别同一业务事务内SQL的调用序列(例如MODULE='OrderService'下连续出现INSERT INTO orders→INSERT INTO order_items→UPDATE inventory) - 注意
DBA_HIST_ACTIVE_SESS_HISTORY默认只保留最近几小时数据(取决于_ASH_DISK_WRITE_INTERVAL和磁盘空间),需确认是否已配置长期归档(DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS不影响ASH)
别忽略PL/SQL过程调用带来的SQL隐身执行
很多高频业务逻辑封装在存储过程中,外部只调一次CALL pkg_order.process(),但内部可能循环执行同一条SQL上百次。这种情况下,AWR里看到的是存储过程对应的SQL_ID(通常是BEGIN ... END;),真正干活的SQL却藏在DBA_HIST_ACTIVE_SESS_HISTORY的TOP_LEVEL_SQL_ID或PLSQL_ENTRY_OBJECT_ID里,AWR本身不记录子SQL的执行次数。
实操建议:
- 查
DBA_HIST_ACTIVE_SESS_HISTORY时,优先关注PLSQL_ENTRY_OBJECT_ID > 0的记录,JOINDBA_OBJECTS拿到包名,再结合SQL_ID定位实际执行的SQL - 对高频
PLSQL_ENTRY_OBJECT_ID,用DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE临时开启模块级跟踪,抓取完整调用栈 - 如果无法修改生产环境,可在测试环境用
DBMS_PROFILER跑典型业务流,导出PLSQL_PROFILER_DATA看各SQL在过程内的执行占比
真正的业务调用频次不是单看某条SQL被执行多少次,而是得把MODULE、ACTION、PLSQL_ENTRY_OBJECT_ID、FORCE_MATCHING_SIGNATURE这几层上下文串起来——漏掉任何一层,看到的都是切片,不是全貌。










