ORA-01555在Oracle 12c存储过程中爆发主因是游标OPEN时固化SCN快照,FETCH耗时过长致所需UNDO被覆盖;隐式/显式游标均会锁定SCN,其有效期延至最后一次FETCH,中间I/O、计算或网络延迟均扩大风险窗口。
ora-01555在oracle 12c存储过程中爆发,90%不是版本问题,而是游标打开(open)瞬间锁定scn快照后,fetch过程太长,导致所需undo被其他事务覆盖。
PL/SQL中SELECT INTO、FOR rec IN (SELECT ...)或OPEN ... FOR都会在执行起始点固化一个SCN。这个快照有效期不取决于SQL执行完的时间,而取决于你最后一次FETCH的时间——哪怕中间做了一秒网络I/O、日志写入或循环内计算,都算进“快照窗口”。
SELECT INTO看似单行,但若WHERE条件没走索引,实际仍会全表扫描+过滤,OPEN到赋值完成之间可能已超undo_retention
BULK COLLECT LIMIT,用FETCH ... INTO逐行取,每轮fetch间隔就是风险窗口12c默认启用INMEMORY和更激进的统计信息自动收集策略,反而可能让旧执行计划失效、优化器误选全表扫描;同时ADG备库同步压力会间接加剧主库UNDO重用频率。
v$sql确认该存储过程对应SQL的plan_hash_value是否近期突变过,突变大概率意味着执行路径劣化DBA_TAB_STATISTICS中相关表的last_analyzed是否早于最近一次大DML,未及时分析易触发错误索引选择INMEMORY,注意INMEMORY_QUERY = ENABLE时,部分谓词下推逻辑可能延长一致性读依赖时间别靠猜,直接查动态视图定位真实耗时:
v$session找运行中的会话:SELECT prev_exec_start, sql_id FROM v$session WHERE program LIKE '%your_proc_name%',算出当前时间与prev_exec_start差值,若明显大于undo_retention(查v$parameter),就是它v$undostat.maxquerylen,如果值为3600,说明已有查询跑满1小时——你的存储过程大概率是其中之一v$transaction.used_ublk,若某事务used_ublk > 50000且start_time早于你存储过程启动时间,它正在挤占UNDO空间真正要命的不是参数调多大,而是游标一开就等于把快照“焊死”在那一刻;哪怕只多等3秒fetch,也可能刚好卡在UNDO块被重用的临界点上。