应查v$session中ACTIVE且等待长的会话,用DBMS_XPLAN.DISPLAY_CURSOR分析实际执行计划,重点关注Rows与E-Rows偏差、等待事件及绑定变量类型匹配。

怎么抓正在跑慢的存储过程“活口”?
别等它执行完再查——90% 的性能问题得在它卡住时现场抓。核心是看 v$session(Oracle)或 sys.dm_exec_requests(SQL Server)里状态为 ACTIVE 且等待时间长的会话。
- Oracle:运行
SELECT sid, serial#, sql_id, event, seconds_in_wait FROM v$session WHERE status = 'ACTIVE' AND username IS NOT NULL ORDER BY seconds_in_wait DESC,重点关注event字段:若为db file sequential read,说明索引路径走得多但块读频繁;若为cursor: pin S wait on X,大概率是硬解析风暴 - SQL Server:查
sys.dm_exec_requests中status = 'running'且wait_time > 5000(毫秒)的请求,结合blocking_session_id判断是否被锁阻塞 - MySQL:用
SHOW PROCESSLIST找State为Waiting for table metadata lock或长时间Updating的线程,注意区分是 DML 还是 DDL 引起的锁
拿到 SQL_ID 后怎么确认执行计划真出了问题?
光看 EXPLAIN 不够——它只给预估,得看真实执行时的统计。关键指标不是“有没有走索引”,而是“走得多不多、准不准”。
- Oracle:用
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('your_sql_id', NULL, 'ALLSTATS LAST')),重点比对Rows(实际返回)和E-Rows(预估),偏差超 10 倍基本说明统计信息过期或绑定变量窥探失效 - MySQL:8.0+ 直接用
EXPLAIN ANALYZE;5.7 用EXPLAIN FORMAT=TRADITIONAL+ 手动代入参数值测试,关注type是否为ALL、key是否为空、rows是否远大于结果集 - SQL Server:开
SET STATISTICS PROFILE ON,看Actual Rows和Estimated Rows差异,同时留意Warnings列是否有Convert提示(隐式转换)
为什么改了 FETCH 还是慢?BULK COLLECT 不等于自动变快
BULK COLLECT 只解决“取数据”这一步的开销,不解决“处理数据”这一步的逻辑缺陷。常见误区是把单行循环改成批量取数,但循环体里仍是单行 DML。
- 错误写法:
BULK COLLECT INTO coll FROM ...; FOR i IN 1..coll.COUNT LOOP UPDATE t SET x = coll(i).x WHERE id = coll(i).id; END LOOP;→ 实际仍是 N 次独立 UPDATE - 正确写法:把 DML 移到循环外,用
FORALL i IN 1..coll.COUNT UPDATE t SET x = coll(i).x WHERE id = coll(i).id→ 转为单次批量操作 - 别忽略
LIMIT值:设太小(如 100)导致分批太碎;设太大(如 100000)可能触发 PGA/内存不足;建议从 5000 起调,观察v$pgastat的total PGA allocated
参数类型不匹配怎么悄悄拖垮性能?
表面看 SQL 写得没问题,但传参类型和字段类型不一致,会触发隐式转换,直接让索引失效。这种问题在开发环境往往不暴露,上线后数据量上来才爆发。
- 典型场景:
WHERE order_id = :p_id,而p_id是VARCHAR2,表中order_id是NUMBER→ Oracle 自动转成TO_NUMBER(:p_id),索引无法使用 - 验证方法:把存储过程中该 SQL 单独拿出来,把
:p_id替换成字面量(如12345),再跑EXPLAIN PLAN,如果这时走了索引,问题就出在绑定类型 - 临时解法加提示
/*+ INDEX(t idx_order_id) */,但长期必须统一类型,或显式写成WHERE order_id = TO_NUMBER(:p_id)
真正卡住的地方,往往不在存储过程开头那几行声明,而在某条看似普通的 UPDATE 语句里——它没走索引、被锁住了、或者正因参数类型错位,在全表扫描。定位时别跳过“执行计划里 rows 和实际返回行数差多少”这个细节,那是最诚实的信号。


















