《Oracle编程艺术》学习笔记(21)-ORA-01555:snapshot too old 错误

本文深入探讨了Oracle多版本模型下,导致ORA-01555错误的三个主要原因:UNDO段太小、提交太频繁和延迟的块清除。提供了针对这些问题的解决方案,包括优化查询、合理设置undo管理参数、增加UNDO表空间大小等措施,以及在遇到延迟块清除情况时的应对策略。
Oracle的多版本模型会使用回滚段(UNDO段)数据依照语句或事务(取决于隔离模式)开始时的原样来重建块。
回滚段是循环使用的,当事务提交以后,该事务占用的回滚段事务表会被标记为非活动,回滚段空间可以被覆盖重用。

造成ORA-01555错误有三个可能原因:UNDO段太小;提交太频繁;延迟的块清除。

UNDO段太小
有2个解决办法,
1)减少查询的运行时间(调优)。应该首先尝试这种方法。这样就能降低对undo段的需求,不需求太大的undo段。
2)允许UNDO表空间扩大,为之留出扩展的空间,并增加UNDO保持时间。

管理系统中的undo有两种方法,自动undo管理(Automatic undo management)和手动undo管理(Manual undo management)。
可以通过undo_management参数来设定(AUTO表示自动管理,MANUAL表示手工管理)。推荐使用自动管理。

在自动管理下,通过undo_retention参数告诉Oracle要把undo保留多长时间,要大于执行运行时间最长的事务所需的时间,可以用V$UNDOSTAT来确定长时间运行的查询的持续时间。另外,要确保磁盘上已经预留了足够的空间,使undo段能根据所请求的undo_retention增大。
Oracle会根据并发工作负载来确定要创建多少个undo段,以及每个undo段应该多大。数据库甚至在运行时可以在各个undo段之间重新分配区段。

提交太频繁
如果在读取表的同时,另外的会话在修改这个表,就会同时生成查询所需的undo信息,查询可能会利用这些undo信息来得到读一致视图。如果另外的会话提交了所做的更新,就会允许系统重用刚刚填写的undo段空间,就有可能擦除了旧的undo数据。如果查询随后要用到这些undo信,就会收到一个ORA-01555:snapshot too old错误消息。
所以提交的太频繁是造成ORA-01555错误的一个可能原因(比如对一个块上的10行数据,每次修改1行并提交,就会对这个块生成10次UNDO镜像数据)。

延迟的块清除
什么是块清除?http://blog.youkuaiyun.com/fw0124/article/details/6901732
发生延迟块清除情况下,如果一个块已被修改,下一个会话访问这个块时,可能必须查看最后一个修改这个块的事务是否还是活动的。一旦确定该事务不再活动,就会完成块清除。
Oracle会从块首部的ITL事务槽(该事务槽指向回滚段段头的事务槽),确定前一个事务所用的回滚段,然后试图从这个回滚段首部的事务槽来获得该事务的提交SCN,如果事务的前镜像信息已经被覆盖,并且查询SCN也小于回滚段中记录的最小SCN,那么Oracle将无法判断查询SCN和事务提交SCN的大小,此时出现延迟块清除导致的ORA-01555错误。

可见,要从一个延迟的块清除收到ORA-01555错误,以下条件都必须满足:
· 首先做了一个修改并COMMIT,块没有完成自动块清除(例如修改了太多的块,在SGA块缓冲区缓存的10%中放不下)。
· 其他会话没有接触这些块,而且在我们这个“倒霉”的查询命中这些块之前,任何会话都不会接触它们。
· 从SCN=t1开始开始一个长时间运行的查询,这个查询最后会读到上面所说的未完成块清除的其中的一些块。由于读一致性必须将数据回滚到SCN=t1时的状态。
· 开始查询时,上面执行修改的事务的事务条目可能还在undo段的事务表中。但是查询期间,系统中执行了多个提交。执行事务没有接触上面这些已修改的块(如果确实接触到,就会执行块清除,也就不存在问题了)。由于出现了大量的COMMIT,undo段中的事务表要回绕并重用事务槽,现在最初执行修改的事务在回滚段的事务表中的条目已经被覆盖。
· 由于提交太多,undo段中记录的最低SCN现在超过了t1(高于查询的读一致SCN)。
现在,如果查询到达最初已经修改并提交的某个块,就会遇到麻烦。由于最初执行修改的事务条目已经被覆盖,所以无法查询最初执行修改的事务的SCN,而且undo段中记录的最低SCN现在超过了t1,在这种特殊的情况下,查询无法确定块的COMMIT SCN是大于还是小于t1,也就不清楚查询能否使用这个块映像。这就导致了ORA-01555错误。

如果在一个表执行SELECT时(没有应用其他DML操作)出现了ORA-01555错误,就是因为延迟的块清除引起的。解决办法:
1)减少查询的运行时间(调优)。
2)保证使用的事务“大小适当”。确保没有不必要地过于频繁地提交。
3)使用DBMS_STATS扫描相关的对象,加载之后完成这些对象的清理。由于块清除是极大量的UPDATE或INSERT造成的,所以很有必要这样做。
4)允许UNDO表空间扩大,为之留出扩展的空间,并增加UNDO保持时间。

<think> 我们已知ORA-01555错误的原因是:一致性读所需的回滚数据被覆盖(在自动撤销管理模式下,撤销保留时间不足或撤销表空间过小导致) 根据引用[1]的建议,在自动撤销管理模式下,应增加undo_retention设置。此外,还可能涉及撤销表空间大小的问题。 解决思路: 1. 检查当前undo_retention设置,考虑适当增加。 2. 检查撤销表空间的使用情况,考虑扩大表空间或添加数据文件。 3. 检查是否有长时间运行的查询,优化查询以减少一致性读所需的时间。 4. 考虑使用闪回查询或其他技术避免该错误。 具体步骤: 步骤1:查看当前的undo_retention参数 ```sql SHOW PARAMETER undo_retention; ``` 步骤2:查看撤销表空间的使用情况和数据文件信息 ```sql SELECT tablespace_name, status, SUM(bytes)/1024/1024 "Size(MB)", SUM(maxbytes)/1024/1024 "MaxSize(MB)" FROM dba_data_files WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace') GROUP BY tablespace_name, status; SELECT tablespace_name, file_name, bytes/1024/1024 "Size(MB)", maxbytes/1024/1024 "MaxSize(MB)", autoextensible FROM dba_data_files WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace'); -- 查看撤销表空间的使用情况 SELECT b.tablespace_name, b.seg_file_name, b.seg_blk_no, a.used_ublk, a.used_urec FROM v$transaction a, v$rollstat b WHERE a.xidusn = b.usn; ``` 步骤3:根据检查结果调整 - 如果撤销表空间使用率很高,且自动扩展已开启但空间不足,考虑手动增加数据文件大小或添加数据文件。 - 如果自动扩展未开启,建议开启自动扩展并设置最大大小。 示例:添加数据文件到撤销表空间 ```sql ALTER TABLESPACE undotbs1 ADD DATAFILE '/path/to/undo02.dbf' SIZE 2G AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED; ``` 步骤4:增加undo_retention的值(例如增加到10800秒,即3小时) ```sql ALTER SYSTEM SET undo_retention=10800 SCOPE=BOTH; ``` 注意:undo_retention只是一个目标值,如果撤销表空间压力大(空间不足),即使设置了较大的undo_retention,Oracle也可能覆盖未过期的数据。因此,确保撤销表空间足够大。 步骤5:优化长时间运行的查询 - 检查AWR报告或长时间运行的会话,优化相关SQL。 步骤6:如果上述方法不能解决,考虑使用闪回查询(如果启用)或者使用其他技术(如物化视图)避免长查询。 此外,还可以考虑以下高级方法: - 使用RETENTION GUARANTEE(确保撤销表空间保留数据,即使空间紧张也不覆盖): ```sql ALTER TABLESPACE undotbs1 RETENTION GUARANTEE; ``` 注意:这可能导致事务因撤销空间不足而失败,需谨慎。 总结:ORA-01555错误的解决核心是确保在查询需要一致性读的时间内,撤销数据不被覆盖。因此,需要从撤销保留时间和撤销表空间大小两方面入手,同时优化查询。 §§相关问题§§ 1. 如何监控Oracle撤销表空间的使用情况? 2. 在Oracle中,undo_retention参数的具体含义是什么? 3. 如何优化长时间运行的查询以避免ORA-01555错误? 4. 什么是Oracle的闪回查询?如何使用它来避免ORA-01555错误? </think> ### 解决ORA-01555错误的方法 ORA-01555错误(快照过旧)通常发生在Oracle数据库需要读取被覆盖的撤销数据时,主要原因是撤销表空间不足或保留时间过短。以下是具体解决步骤: #### 1. **调整`undo_retention`参数** - **查看当前值**: ```sql SHOW PARAMETER undo_retention; ``` - **适当增加保留时间**(建议至少2倍于最长查询时间): ```sql ALTER SYSTEM SET undo_retention = 1800 SCOPE=BOTH; -- 单位:秒(示例设为30分钟) ``` #### 2. **扩展撤销表空间** - **检查表空间使用率**: ```sql SELECT tablespace_name, status, ROUND(SUM(bytes)/1024/1024) "Size(MB)", ROUND(SUM(maxbytes)/1024/1024) "MaxSize(MB)" FROM dba_data_files WHERE tablespace_name = 'UNDOTBS1' -- 替换为实际表空间名 GROUP BY tablespace_name, status; ``` - **扩容操作**: ```sql ALTER DATABASE DATAFILE '/u01/oradata/undotbs01.dbf' RESIZE 10G; -- 扩容文件 ``` 或添加新文件: ```sql ALTER TABLESPACE undotbs1 ADD DATAFILE '/u01/oradata/undotbs02.dbf' SIZE 5G AUTOEXTEND ON; ``` #### 3. **优化长时间查询** - 检查并优化执行时间过长的SQL: ```sql SELECT sql_id, elapsed_time/1000000 "sec", sql_text FROM v$sql ORDER BY elapsed_time DESC; ``` - 为复杂查询添加`/*+ MATERIALIZE */`提示,减少撤销数据需求。 #### 4. **启用保留保证**(谨慎使用) ```sql ALTER TABLESPACE undotbs1 RETENTION GUARANTEE; -- 确保数据保留 ``` > ⚠️ 此操作可能导致事务因空间不足失败,需配合表空间扩容使用[^1]。 #### 5. **其他建议** - **监控撤销统计**: ```sql SELECT TO_CHAR(begin_time, 'HH24:MI') time, tuned_undoretention FROM v$undostat ORDER BY begin_time DESC; ``` - **减少批量提交频率**:避免短时间产生大量撤销数据。 > **根本原因**:当查询执行时间超过撤销数据的保留时间时,所需的数据回滚段已被覆盖[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值