awr中executions榜首多为低价值语句,优化无效;应基于force_matching_signature聚合、过滤干扰sql,并结合ash分钟级分析识别真实轮询或重试问题。

AWR里SQL ordered by Executions榜首的,90%不是业务SQL,而是SELECT 1、COMMIT、INSERT INTO LOG等低价值语句——直接优化它们,对响应时间和吞吐量几乎没影响。
为什么Executions高不等于业务逻辑有问题
Oracle的EXECUTIONS统计的是语句被数据库执行的次数,不是应用发起的业务请求数。一次下单操作可能触发:3次SELECT 1 FROM DUAL(连接池心跳)、5次UPDATE ORDER_STATUS(状态轮询)、2次INSERT INTO AUDIT_LOG(日志写入)——这些全算进Executions,但和核心逻辑无关。
常见干扰源包括:
-
MODULE = 'JDBC Thin Client'且PROGRAM含HealthCheck或ConnectionPool -
FORCE_MATCHING_SIGNATURE = 0的短语句(如COMMIT、ROLLBACK、SELECT SYSDATE FROM DUAL) -
SQL_TEXT匹配'SELECT 1%'、'INSERT INTO LOG_%'、'UPDATE %_STATUS WHERE id = :1'
怎么从DBA_HIST_SQLSTAT里筛出真问题SQL
别依赖AWR报告默认的“SQL ordered by Executions”页——它按SQL_ID分组,而MyBatis动态SQL或JPA批量更新会让语义相同的语句产生几十个不同SQL_ID。必须用FORCE_MATCHING_SIGNATURE聚合:
执行以下查询(替换&begin_snap和&end_snap):
SELECT s.sql_id, t.sql_text, SUM(s.executions_delta) exec_total, COUNT(DISTINCT s.sql_id) sql_id_count, s.force_matching_signature FROM dba_hist_sqlstat s JOIN dba_hist_sqltext t USING (sql_id) WHERE s.snap_id BETWEEN &begin_snap AND &end_snap AND s.force_matching_signature != 0 AND t.sql_text NOT LIKE 'SELECT 1%' AND t.sql_text NOT LIKE 'INSERT INTO LOG_%' AND s.module NOT LIKE '%HealthCheck%' GROUP BY s.force_matching_signature, s.sql_id, t.sql_text HAVING SUM(s.executions_delta) > 10000 ORDER BY exec_total DESC;
关键点:
- 用
force_matching_signature代替sql_id做主分组,才能把WHERE status = :1这类语义一致的语句归为一类 -
HAVING SUM(s.executions_delta) > 10000过滤掉噪音,聚焦真正高频行为 - 如果
sql_id_count远大于1(比如50个SQL_ID共用一个签名),说明是绑定变量缺失或NLS参数漂移导致游标无法复用
Executions突增时必须查ASH验证节奏
AWR快照粒度是1小时,根本抓不住秒级轮询。比如每30秒执行一次的SELECT * FROM JUDGE_TASK WHERE STATUS = '0',在AWR里只显示为“3600秒内执行7200次”,看不出周期性——这会误导你去优化SQL本身,而不是干掉轮询逻辑。
正确做法是关联DBA_HIST_ACTIVE_SESS_HISTORY:
SELECT TRUNC(sample_time, 'MI') minute_slot, COUNT(*) exec_per_minute FROM dba_hist_active_sess_history h JOIN dba_hist_sqlstat s ON h.sql_id = s.sql_id WHERE s.force_matching_signature = &target_sig AND h.sample_time > SYSDATE - 1/24 GROUP BY TRUNC(sample_time, 'MI') ORDER BY exec_per_minute DESC;
如果结果出现稳定在2或4(即每30秒或15秒一次),基本可断定是未加缓存的轮询任务;若数值呈尖峰状(如某分钟突然跳到300次),则可能是重试机制失控或前端重复提交。
最容易被忽略的细节:EXECUTIONS_DELTA是差值,不是绝对值
DBA_HIST_SQLSTAT.executions_delta记录的是两个快照之间的增量,不是累计值。如果你跨多个快照求和却没按snap_id严格排序,会重复计算或漏算。更麻烦的是:某些SQL在快照边界刚好被老化出共享池,executions_delta可能为负或异常大——这时得结合v$sql里的executions和last_active_time交叉验证实时频次。没有分钟级ASH佐证的Executions数据,优化动作大概率打偏。











