一次典型的 SQL 性能问题排查:临时表导致的隐藏性能陷阱

在日常数据库运维过程中,经常会遇到这样一类问题:

数据库整体性能正常,但某一条 SQL 在业务系统中执行极慢,

然而 DBA 在后台手工执行时,却发现 执行速度非常快。

这类问题往往不在"数据库整体性能",而隐藏在具体 SQL 的执行细节和业务执行环境差异中。

本文记录了一次真实的 SQL 性能排查过程,最终定位到 临时表使用不当 所引发的问题。

一、问题现象:整体正常,单条 SQL 异常

客户业务系统运行过程中,出现如下现象:

• 数据库整体运行状态正常

• CPU、IO、等待事件均无明显异常

• 仅有 一条业务 SQL 在前台执行非常缓慢

• 同一条 SQL 在后台手工执行时,执行速度却非常快

从表象来看,这并不像是数据库整体性能瓶颈,更像是某条 SQL 在特定执行场景下存在问题。

二、通过 AWR 报告定位性能热点

为进一步确认问题,通过 AWR 报告(使用 @?/rdbms/admin/awrrpti.sql 生成)对系统性能进行分析。

AWR 报告显示:

• 系统的主要性能消耗集中在 一条 SQL

• 该 SQL 单次执行时间约为 406,814 ms

从执行时间来看,这条 SQL 明显是当前系统的主要性能瓶颈。

三、执行计划"完美",却解释不了慢的问题

继续查看该 SQL 的执行计划,发现一个容易让人放松警惕的情况:

• 执行计划 cost 不大

• 各个执行步骤看起来都非常合理

• 没有明显的全表扫描或低效访问路径

从执行计划角度判断,这条 SQL 理论上不应该这么慢。

但事实是:

SQL 确实执行得非常慢。

四、执行统计信息暴露异常:buffer gets 极高

在进一步查看 SQL 的执行统计信息后,问题开始显现出来。

该 SQL 的统计信息显示:

• buffer gets 达到 595,764,242

• 这是一个极不正常的数值

而从数据规模来看:

• SQL 中涉及的最大表 GL_VERIFY_LOG 只有 17,710 行

• 其他表的数据量更是可以忽略不计

在如此小的数据规模下,却出现如此高的 buffer gets,显然不符合正常逻辑。

五、常规思路排查:统计信息并非根因

第一反应自然是怀疑:

是否因为对象统计信息不准确,导致优化器判断失误?

于是对 SQL 涉及的所有对象进行了 100% 采样的统计信息收集。

但结果是:

• SQL 执行性能没有任何改善

• buffer gets 依然很高

同时可以确认:

• SQL 未使用绑定变量

• 不存在 bind peeking 导致的执行计划不稳定问题

• 后台执行时显示的执行计划,与 AWR 中的执行计划一致

此时,执行计划、统计信息、SQL 写法,似乎都"没有问题"。

六、关键细节:执行计划中的 Dynamic Sampling

在反复对比前台与后台执行差异时,注意到一个细节:

后台执行该 SQL 时,执行计划中出现了 Dynamic Sampling(动态采样)。

这是一个非常关键的信号。

在 Oracle 中,涉及临时表的 SQL,往往会触发动态采样,以便在运行时获取更准确的数据分布信息。

这一现象直接将排查方向指向了 SQL 中可能存在的临时表。

七、问题根因确认:临时表数据量差异

继续深入检查 SQL 涉及的对象,最终确认:

• SQL 中使用了临时表 ASSTEMPORA

• 前台业务程序执行 SQL 前,会向该临时表中加载 大量数据

• 后台 DBA 手工执行 SQL 时,该临时表 数据为空

这就解释了所有现象:

• 前台执行:

• 临时表数据量大

• SQL 执行过程中产生大量 buffer gets

• 导致执行时间极长

• 后台执行:

• 临时表无数据

• SQL 执行路径看起来"非常理想"

• 执行时间极短

八、优化方案:为临时表补充索引

问题的本质在于:

临时表在高数据量参与 SQL 计算时,缺失必要索引。

针对该问题,在临时表 ASSTEMPORA 上创建索引:

复制代码
CREATE INDEX ASSTEMPORA_IDX ON ASSTEMPORA (assid);

索引创建完成后:

• 前台 SQL 执行时间明显缩短

• buffer gets 大幅下降

• 业务模块性能恢复正常

问题得到彻底解决。

九、小结:临时表同样需要"正式对待"

通过这次问题排查,可以得到几个非常重要的经验结论:

  1. 执行计划看起来没问题,并不代表 SQL 一定高效

  2. 前台与后台执行差异,往往来自 数据状态不同

  3. 临时表一旦承载真实业务数据,就必须像普通表一样设计索引

  4. 执行计划中的 Dynamic Sampling 是一个非常重要的排查线索

很多 SQL 性能问题,并不是写得复杂,而是在真实业务场景下,被放大了原本被忽略的设计缺陷。

相关推荐
IT 乔峰10 小时前
分享一个负载均衡的NDB高可用集群架构+部署详细说明
数据库·架构·负载均衡
丁丁点灯o10 小时前
oracle中基于正则表达式匹配规则提取子串的函数REGEXP_SUBSTR
数据库·oracle·正则表达式
木风小助理10 小时前
Android 数据库实操指南:从 SQLite 到 Realm,不同场景精准匹配
jvm·数据库·oracle
Elseide艾思10 小时前
数字经济专利数据库(1994年更新至今)
数据库
optimistic_chen10 小时前
【Redis系列】事务特性
数据库·redis·笔记·缓存·事务
踏月的造梦星球10 小时前
浅究Oracle迁移至DM8产生数据文件膨胀的原因
数据库·oracle
DBA小马哥10 小时前
时序数据库迁移替换与选购指南
数据库·时序数据库
Knight_AL10 小时前
深入解析数据库四大事务隔离级别及其实际应用
服务器·数据库·oracle
xj75730653310 小时前
《精通Django》 第三章 Django模板
数据库·django·sqlite