1. ORA-01555 快照过旧到底是什么为什么长查询总在 undo 表空间上翻车先说结论ORA-01555 不是数据坏了也不是 SQL 写错了而是 Oracle 在给你构造一致性读镜像时发现需要的回滚数据已经被覆盖掉了。你查的是几分钟前的数据但 undo 表空间里那段前镜像已经没了Oracle 只能报错。这个报错在真实生产里非常典型。比如你有一个跑批报表一条 SQL 要扫几千万行跑 40 分钟同时业务侧还在高频 update 同一批表。查询开始时 Oracle 记录了一个 SCN之后每读一个块都要判断这个块是不是在查询开始之后被改过。如果被改过就得去 undo 里找前镜像把块还原成查询开始那一刻的样子。undo 里的前镜像有保留时间默认由 undo_retention 控制但真正决定它能不能留住的是 undo 表空间有没有被撑爆。这里有个很多人踩过的坑以为设了 undo_retention10800 就万事大吉。实际上在默认的 NOGUARANTEE 模式下undo_retention 只是一个“尽力而为”的目标。当 undo 表空间快满、又有新事务需要空间时Oracle 会优先覆盖那些已经超过保留时间的前镜像如果空间还不够甚至会覆盖还没到期的。这时候长查询再去读就撞上 ORA-01555。所以复现这个错误的核心思路就两条一是制造一个“长查询”让游标一直开着不取完二是制造“undo 被快速消耗并覆盖”的压力让前镜像在查询还没结束时就消失。理解了这两点你就能在测试库上稳定复现而不是靠运气。适合谁看正在被 ORA-01555 困扰的 DBA、做数据迁移或报表开发的同学、以及想搞懂 undo 表空间 guarantee 和 autoextend 到底怎么配的人。下面我会用两个会话Session1 长查询、Session2 制造 undo 压力完整走一遍复现路径再给出 guarantee 和 autoextend 两种解决配置最后把常见报错对照着排一遍。需要说明的是复现实验请在测试库或可回滚的环境做别在生产库上直接切 undo 表空间。另外如果你在本地用命令行工具或 AI 辅助编码来管理这些脚本可以借助 TaoToken 这类聚合入口统一管理模型调用和密钥后面配置章节我会给出具体写法。2. 复现前的环境准备与 TaoToken 接入前置配置复现 ORA-01555 之前先把环境理清楚。你需要一个能登录的 Oracle 实例10g、11g、12c、19c 都可以报错文本略有差异但机制一致以及两个能同时连上去的会话。我用的是 SQL*Plus你也可以用 SQL Developer 开两个 worksheet。先建一张最简单的测试表数据量不用大关键是让 update 循环能持续消耗 undo-- Session1 和 Session2 都能访问 create table t (id number, name varchar2(20)); insert into t values (1, a); insert into t values (2, b); commit;然后确认当前 undo 表空间和 retention 设置这是后面判断问题的基础show parameter undo你会看到类似NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_management string AUTO undo_retention integer 900 undo_tablespace string UNDOTBS1undo_retention 单位是秒900 就是 15 分钟。记住这个值后面 guarantee 实验会用到。接下来是 TaoToken 的前置配置。如果你平时用 AI 辅助写 SQL、生成排障脚本或者用 Claude Code、Cline 这类工具做数据库运维辅助建议把模型调用统一走一个入口省得每个工具单独配 key。TaoToken 的 API 地址是https://taotoken.net/api控制台在https://taotoken.net/console密钥在https://taotoken.net/api-keys生成。以 Claude Code 为例配置三件套是 Base URL、API Key、Model ID。在 settings 里写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的密钥, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }如果你用的是 Cline 或 Roo Code 这类支持 MCP 的插件配置片段类似{ mcpServers: { taotoken: { url: https://taotoken.net/api, headers: { Authorization: Bearer sk-你的密钥 } } } }Codex 用户则在~/.codex/auth.json里写{ base_url: https://taotoken.net/api, api_key: sk-你的密钥, model: gpt-5 }这三件套缺一不可Base URL 决定请求发到哪API Key 决定身份Model ID 决定用哪个模型。配好之后你可以先用模型对话页面https://taotoken.net/chat验证一下能不能正常返回再去接工具。环境准备好之后我们进入复现环节。核心是让 Session1 开一个游标但不取完Session2 疯狂 update 把 undo 撑爆。3. 可复制配置构造长查询与 undo 表空间 autoextend 冲突场景这一节是复现的核心我按会话拆开写你照着敲就能触发 ORA-01555。3.1 Session1开一个不取完的游标在 Session1 里执行variable c refcursor; exec open :c for select * from t;注意这里只 open不 fetch、不 print。游标一直开着Oracle 就认为这个查询还在进行中它需要的一致性读镜像会一直保留到游标关闭。这就是“长查询”的最小模型。3.2 Session2切到小 undo 表空间并禁止自动扩展为了让 undo 快速被覆盖我们新建一个很小的 undo 表空间并且关掉 autoextend。这一步是复现的关键生产上很多 ORA-01555 就是因为 undo 表空间设了固定大小又没开自动扩展。create undo tablespace undotbs2 datafile /u01/app/oracle/oradata/ORCL/undotbs2.dbf size 1m autoextend off; alter system set undo_tablespaceundotbs2;路径按你自己的环境改Windows 下就是F:\oracle\product\10.2.0\oradata\zxntal\undotbs2.dbf这种写法。size 给 1m 是为了快速撑满实际测试可以给 5m 或 10m看你 update 的量。如果你已经有多个 undo 表空间也可以直接把现有数据文件 resize 小并关掉自动扩展alter database datafile 7 resize 1M; alter database datafile 7 autoextend off;3.3 Session2循环 update 消耗 undo接着在 Session2 里跑一个循环每次 update 都 commit这样每轮都会产生新的 undo 记录同时旧的前镜像会被标记为可覆盖begin for i in 1..10000 loop update t set id i; commit; end loop; end; /10000 次循环足够把 1m 的 undo 表空间撑爆。跑的过程中你可以另开一个会话查 undo 使用率select tablespace_name, bytes/1024/1024 mb from dba_free_space where tablespace_name UNDOTBS2;3.4 Session1取游标触发 ORA-01555等 Session2 跑完回到 Session1print c;这时候大概率会看到ERROR: ORA-01555: 快照过旧: 回退段号 13 (名称为 _SYSSMU13$) 过小回退段号和名称每次不一样但报错类型一致。到这里复现就成功了。3.5 两种解决配置guarantee 与 autoextend复现出来之后解决路径有两条对应两种配置。第一种是强制 guarantee。它让 undo 表空间必须保留 undo_retention 时间内的前镜像空间不够就报 ORA-30036而不是覆盖alter tablespace undotbs2 retention guarantee;改完之后再跑一遍 Session2 的循环你会看到ORA-30036: 无法按 8 扩展段 (在还原表空间 UNDOTBS2 中) ORA-06512: 在 line 4这说明 guarantee 生效了它宁可让写事务失败也不覆盖长查询需要的前镜像。生产上要谨慎用因为可能导致业务写入被阻塞。第二种是让 undo 表空间自动扩展alter database datafile 7 autoextend on;开了 autoextend 之后undo 空间不够就自动长大前镜像能保留更久长查询就能顺利取完。再跑一遍-- Session1 exec open :c for select * from t; -- Session2 跑循环 -- Session1 print c;这次会正常返回ID NAME ---- ---- 10000 a 10000 b两种方案各有适用场景guarantee 适合对一致性读要求极高、能接受写入失败的场景autoextend 适合 undo 空间有富余、不想让业务报错的场景。实际生产里更常见的是两者结合设一个合理的 undo_retention开 autoextend 并设 maxsize 上限再根据业务峰值评估是否加 guarantee。4. 验证请求与成功结果确认 undo_retention 与 guarantee 真正生效配完参数不代表生效得验证。这一节给你几个可复制的查询和动作确认 undo 表空间状态、retention 设置、以及长查询是否真的不再报错。先查表空间的 retention 模式select tablespace_name, retention from dba_tablespaces where tablespace_name UNDOTBS2;返回GUARANTEE说明 guarantee 已开NOGUARANTEE说明没开。这个字段是判断 guarantee 是否生效的第一手依据。再查数据文件的 autoextend 状态select file_name, autoextensible, maxbytes/1024/1024 max_mb from dba_data_files where tablespace_name UNDOTBS2;autoextensible是 YES 就说明自动扩展开了。maxbytes是上限如果设成 32767m 这种基本等于不限。生产上建议设一个明确上限比如 20G避免 undo 无限膨胀把磁盘吃满。然后查 undo_retention 的当前值show parameter undo_retention如果你想让前镜像保留更久可以动态调整alter system set undo_retention 10800;10800 秒就是 3 小时。注意这个值不是越大越好它直接决定 undo 表空间需要多大。粗略估算undo 空间 ≈ undo_retention × 每秒产生的 undo 量。你可以用下面这个查询看当前 undo 生成速率select begin_time, undoblks, maxquerylen, tuned_undoretention from v$undostat order by begin_time desc fetch first 10 rows only;maxquerylen是最长查询时长秒tuned_undoretention是 Oracle 自动调优后的建议保留时间。如果maxquerylen经常接近或超过你的 undo_retention那 ORA-01555 迟早会来。验证长查询是否恢复最直接的办法就是重跑第 3 节的实验Session1 开游标Session2 跑 update 循环Session1 print。如果返回正常数据而不是 ORA-01555说明配置生效。还有一个容易被忽略的点guarantee 和 autoextend 同时开的时候如果 autoextend 到了 maxsize 上限undo 还是会被撑满这时候 guarantee 会让写事务报 ORA-30036。所以 maxsize 要留足余量或者配合监控告警。如果你用 AI 工具辅助生成这些验证脚本可以在 TaoToken 的模型对话页面直接让它帮你写 v$undostat 的分析 SQL省得自己拼。密钥在https://taotoken.net/api-keys管理接入文档在https://taotoken.net/doc。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth 对照复现和配置过程中除了 ORA-01555 本身还会遇到一些周边报错。这一节按真实报错文本对照排查。ORA-30036 无法扩展段这是开了 guarantee 之后最常见的。含义是 undo 表空间没有足够空间保留 undo_retention 内的前镜像写事务被拒绝。解决方向要么调大 undo 表空间或开 autoextend要么降低 undo_retention要么排查是不是有异常长的事务在占用 undo。别直接关 guarantee 了事先搞清楚为什么 undo 不够。ORA-01555 反复出现但 undo 空间看着够检查是不是有并行查询或者游标没关。有些应用 open 了游标忘记 close导致一致性读镜像一直需要保留。查v$open_cursor和v$session里长时间 active 的会话。401 Unauthorized如果你在配置 TaoToken 接入时遇到 401先检查 API Key 是否复制完整、有没有多余空格。密钥在https://taotoken.net/api-keys重新生成一个再试。Base URL 必须是https://taotoken.net/api不要带路径后缀。local proxy failed这个报错通常出现在本地工具走代理配置时。检查你的环境变量里有没有残留的 HTTP_PROXY/HTTPS_PROXY或者工具自身的代理设置。TaoToken 的接入不需要额外代理直连即可。把代理配置清掉再试。reading choices 相关报错这类报错一般出现在调用模型接口解析响应时说明返回体格式和客户端预期不一致。先确认 Model ID 写对了比如 Claude 系列要用claude-sonnet-4-20250514这种完整 ID不要简写。再确认请求头里的 Content-Type 和 Authorization 格式正确。OAuth 相关报错如果你用的是需要 OAuth 授权的工具检查 token 是否过期。TaoToken 的 API Key 方式是 Bearer Token不需要走 OAuth 流程。如果工具强制 OAuth看它是否支持自定义 Base URL 加 API Key 的模式。切换 undo 表空间后旧会话报错alter system set undo_tablespace只对新事务生效已经开着的事务还在旧表空间。复现实验里 Session1 的游标是在切换前开的所以它用的还是旧 undo。这也是为什么复现能成功——旧 undo 被切走后前镜像更容易丢。生产上切 undo 表空间要选低峰期并确认没有长事务。autoextend on 之后 undo 还是不够检查 maxbytes 是不是设太小或者磁盘空间不足导致扩展失败。查dba_data_files的maxbytes和操作系统磁盘剩余空间。排查顺序建议先看报错文本ORA 开头的查 v$undostat 和 dba_tablespaces接入类的先查密钥和 Base URL再查网络和代理。把这两类分开别混在一起查。6. 从复现到生产把 ORA-01555 治理落到日常巡检复现只是手段真正有价值的是把治理动作固化到日常。我给你几个可以直接用的巡检项。第一每天查一次 v$undostat看 maxquerylen 和 tuned_undoretention 的走势select to_char(begin_time,yyyy-mm-dd hh24:mi) bt, undoblks, maxquerylen, tuned_undoretention from v$undostat where begin_time sysdate - 1 order by begin_time;如果 maxquerylen 持续增长说明有查询越跑越久要么优化 SQL要么调大 undo_retention。第二给 undo 表空间设一个合理的 autoextend 和 maxsize别用默认的无限扩展alter database datafile /u01/app/oracle/oradata/ORCL/undotbs01.dbf autoextend on next 100m maxsize 20g;第三对关键报表库评估是否开 guarantee。开了之后要配套监控 ORA-30036一旦出现说明 undo 空间规划不够。第四应用侧排查长事务和未关闭游标。很多 ORA-01555 根因不在数据库参数而在应用代码。让开发同学确认有没有在循环里反复 open 游标不 close有没有大事务长时间不 commit。第五如果你用 AI 辅助做巡检脚本生成可以把上面这些查询整理成模板通过 TaoToken 的 Coding Plan 让模型帮你扩展成完整的巡检报告脚本。Coding Plan 入口在https://taotoken.net/coding-plan适合长期做数据库运维自动化的场景。最后说个我自己的经验ORA-01555 最容易被误判成“undo 太小”然后无脑调大 undo_retention。实际上先看 v$undostat 的 maxquerylen再决定是优化查询还是调参数能省很多空间。undo 表空间不是越大越好它和你的业务写入量、查询时长直接相关算清楚再动手。