Oracle undo我们需要掌握什么
《Oracle undo我们需要掌握什么》
引言:undo 是Oracle数据库的重要组件,刚入门的朋友建议要把undo的原理和机制理解明白,尤其是和redo组件的区别和联系。了解undo就相当于对oracle恢复有了一半的理解。下面我们开始学习Oracle undo需要掌握什么!
更多的精彩文章请垂询 www.leonarding.com blog,欢迎大家来探讨交流
“分享技术~成就梦想”
一 大话UNDO
Hi 大家好,我是Oracle 的无敌小安[中文名(small undo[英文名),首先我先来介绍一下自己吧,我诞生于一个大家庭Oracle,现在的一把手拉里.埃里森就是我的缔造者,我的诞生可谓Oracle立下了汗马功劳,使Oracle开拓缰野攻城略地!我的诞生是为了解决三个大问题,事物回滚,实例恢复,查询一致性。这样的功能使Oracle成为了关系型数据库中的佼佼者。
例如:读不会被写所阻塞,当我们读取的数据块正好被他人修改时,我们就可以找到undo段里保存的前映像来维护一致性。而其他数据库,sql server mysql等都没有undo段,也就是说它们查询时可能被阻塞。
Undo和Redo区别
好多人尤其是刚刚入门的朋友,总会把这两个概念搞混淆。
Redo:是基于安全考虑的,会记录数据库的所有变化,当数据被误修改时,使用redo可重新生成,事物重做。是前滚,就是从无到有的新创建。一个新生命的诞生。
Undo:是基于回滚的,当数据被误修改时,可以从修改的新状态回退到老状态,实现事物回滚,相当于撤销操作。是回滚,就像倒录音带一样,把走过的路反向在走一遍回到原点。
Undo目的:1.事物回滚:rollback
2.实例的恢复:掉电,死机,强制关库,把没有提交的事物全部回滚
3.查询一致性:读不会被写所阻塞
Undo段:采用LRU最近最少使用算法来循环覆盖使用,它的块有active和inactive和new状态,如果块的状态为inactive那么后续的数据就可以覆盖它了。如果空间不够Oracle自动分配新空间。
分配:Oracle是按顺序循环使用的,不允许跨区覆盖。
回收:Oracle也是按顺序回收的,不允许跨区回收。
Rollback和Commit标识位都一样,都代表事物的结束
Rollback:表示会回滚从上一次提交到现在的所有事物
二 数据库版本
SYS@LEO1> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
三 示例演示回滚是否产生REDO日志。
原理解释:首先向大家明确一点,redo的产生机理是因为底层数据块的变化而产生的,这个数据块不管是数据文件的还是undo文件的,数据块的变化都会记录在redo日志里面。
OK我们再来看看undo回滚的原理,假设 一个数据块命名为A,这个A里面存放了数据1,现在我们要把这个1->修改->2->修改->3->修改->2->修改->1 步骤
1.先把1复制一份映像存放到undo块上用于回滚,这就是前映像,undo块改变产生redo记录
2.再把数据块上的1修改为2,A改变产生redo记录,现在A中存放的是2
LEO1@LEO1> drop table leo2 purge; 清理环境
Table dropped.
LEO1@LEO1> create table leo2 as select * from leo1 where rownum<10; 创建leo2表只需要9行记录即可
LEO1@LEO1> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# =b.STATISTIC# and a.NAME='redo size';
NAME VALUE
-----------------------------------------------------------------------------------------------------------------------------------
redo size 2362280
这是初始化的值
LEO1@LEO1> update leo2 set object_id=2 where object_id=1; 1->修改->2
1 row updated.
LEO1@LEO1> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# =b.STATISTIC# and a.NAME='redo size';
NAME VALUE
---------------------------------------------------------------------------------------------------------------------------------------------
redo size 2362992
LEO1@LEO1> select 2362992-2362280 from dual; 这是产生的redo量
2362992-2362280
-------------------------
712
3.这时我们又想把2修改为3,还是先把2复制一份映像存放到undo块上用于回滚,这就是第二个前映像,undo块改变产生redo记录
4.再把A中的2修改为3,A改变产生redo记录,现在A中存放的是3
LEO1@LEO1> update leo2 set object_id=3 where object_id=2; 2->修改->3
1 row updated.
LEO1@LEO1> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# =b.STATISTIC# and a.NAME='redo size';
NAME VALUE
-------------------------------------------------------------------------------------------------------------------------------------------
redo size 2363348
LEO1@LEO1> select 2363348-2362992 from dual; 这是产生的redo量
2363348-2362992
---------------------------
356
5.我们又想把3回退为1,那么就需要先把3回退为2,由于我们在undo段上记录了每次改变的前映像,我们直接把前映像回滚回来即可(事物的回滚),使用第二个前映像把A中的3修改为2,A改变会产生redo记录,现在A中存放的是2,因此这种回滚操作也会产生redo日志的,在使用第一个前映像把A中的2修改为1,A改变会产生redo记录,现在A中存放的是1,此时rollback操作完毕事务结束。
我们用语句来实现一下上面的操作,rollback特点会回滚从上次提交到现在的所有事务,3->1
LEO1@LEO1> rollback; 3->修改->2->修改->1
Rollback complete.
LEO1@LEO1> select a.name,b.value from v$statname a,v$mystat b where a.STATISTIC# =b.STATISTIC# and a.NAME='redo size';
NAME VALUE
---------------------------------------------------------------------------------------------------------------------------------------
redo size 2364608
LEO1@LEO1> select 2364608-2363348 from dual; 产生的redo量很大的
2364608-2363348
------------------------
1260
小结:我们要知道rollback和commit的标识位都一样都代表事务结束,同时也都会产生redo日志。
四 示例演示为数据库创建一个新的UNDO表空间。
Oracle 8i 需要手工创建undo表空间
Oracle 9i 自动管理UNDO表空间
Oracle 10g 11g 在创建数据库时,必须一起创建undo表空间
未来自动化是大趋势,Oracle 12c会更加的自动化 更加的智能
SYS@LEO1> show parameter undo
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO Oracle自动管理表空间
undo_retention integer 900 默认保留期15分钟
undo_tablespace string UNDOTBS1 Oracle默认undo表空间
SYS@LEO1> select tablespace_name,autoextensible from dba_data_files;
TABLESPACE_NAME AUT
-------------------------------------------------------------
USERS YES
UNDOTBS1 YES 这也显示当前使用的undo表空间
SYSAUX YES
SYSTEM YES
LEO1 NO
Oracle 特点:可以创建好多个undo表空间,但只能使用其中一个,下面我们来创建一个新undo
SYS@LEO1> select tablespace_name,file_name,bytes/1024/1024,autoextensible from dba_data_files;
TABLESPACE_NAME FILE_NAME BYTES/1024/1024 AUT
----------------------------------------------------------------------------------------------------------------------------------------------
USERS /u01/app/oracle/oradata/LEO1/users01.dbf 5 YES
UNDOTBS1 /u01/app/oracle/oradata/LEO1/undotbs01.dbf 165 YES
SYSAUX /u01/app/oracle/oradata/LEO1/sysaux01.dbf 610 YES
SYSTEM /u01/app/oracle/oradata/LEO1/system01.dbf 700 YES
LEO1 /u01/app/oracle/oradata/LEO1/leo1_01.dbf 400 NO
这是所有表空间文件路径和大小,当前undo表空间165M,我们把新的设置成100M
SYS@LEO1> create undo tablespace undotbs2 datafile '/u01/app/oracle/oradata/LEO1/undotbs02.dbf' size 100M;
Tablespace created.
UNDOTBS2 /u01/app/oracle/oradata/LEO1/undotbs02.dbf 100 NO
为什么设置成100M呢,这个大小因人而异,你可以根据自己系统的情况个性化设计满足需求即可。
SYS@LEO1> alter system set undo_tablespace=undotbs2;如果要使用新的undo表空间,必须切换到该表空间
System altered.
SYS@LEO1> show parameter undo
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO Oracle自动管理表空间
undo_retention integer 900 默认保留期15分钟
undo_tablespace string UNDOTBS2 成为新的默认undo表空间
小结:1.undo是一个很重要的表空间,一个数据库当且仅当只有一个undo表空间,如果我们想使用新的,必须切换到新表空间。
2.我们不能删除当前正在使用的undo表空间,如果删除了数据库就会crash,如果发现空间太小或者undo段出现坏块,你必须先创建一个新的,再从老的切换过去。
五 示例分别说明什么是consistent read和current read?
一致性读这个话题由来已久,通俗的说一致性读,就是你什么时候发出select,不管查询了多长时间,返回的值都应该是你查询时刻时间点的。这个话题是由业务特性所引起的,是基于业务需求而来的,Oracle中由SCAN号顺序来实现
例如我们查询一张leo1表
LEO1@LEO1> drop table leo1 purge; 清理环境
Table dropped
LEO1@LEO1> create table leo1 as select * from dba_objects; 创建leo1表
Table created.
LEO1@LEO1> set time on 我们启动时间点显示
09:44:38 LEO1@LEO1> set autotrace traceonly
09:44:50 LEO1@LEO1> select * from leo1 where object_type='TABLE'; 我们看一下执行计划
2818 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2716644435
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3003 | 607K| 287 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| LEO1 | 3003 | 607K| 287 (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_TYPE"='TABLE')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1218 consistent gets
0 physical reads
0 redo size
149962 bytes sent via SQL*Net to client
2580 bytes received via SQL*Net from client
189 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2818 rows processed
09:45:04 LEO1@LEO1>
我们从09:44:50发出select语句,到查询到结果是09:45:04,中间经过了14秒,如果这14秒内有另外的用户去修改我们查询的数据块,那么得到的结果是修改后的呢,还是修改前的呢,从业务的角度看,我们查询的是09:44:50的select,那么不管查了多长时间,我们就想要这个时间点的结果,即查什么时候的就得到什么时候的结果就叫一致性读。
一致性读解决方案:就利用到了回滚段,当我们查询时发现这个数据块正在被修改,那么我们就要跳到回滚段上去读取它的前映像,结果不会因为块修改而改变。这就是著名的“读不会被写所阻塞定理”
Select统计信息里反应出的一致性读
0 db block gets 当前读0个块
1218 consistent gets 一致性读1218个块
当前读,什么是当前读,当前读就是我们操作的数据块一定是最当前的状态,这就会产生锁,防止多个会话同时操作一个数据块,谁先获得块谁就拥有修改权,其他会话就要等待。
例如我们修改一张leo1表
10:13:24 LEO1@LEO1> update leo1 set object_type='leonarding' where object_type='TABLE';
2818 rows updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 3524047104
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 12 | 132 | 287 (1)| 00:00:04 |
| 1 | UPDATE | LEO1 | | | | |
|* 2 | TABLE ACCESS FULL| LEO1 | 12 | 132 | 287 (1)| 00:00:04 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='TABLE')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
285 recursive calls
12121 db block gets
3126 consistent gets
13 physical reads
2273320 redo size
837 bytes sent via SQL*Net to client
825 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
2818 rows processed
10:13:27 LEO1@LEO1>
我们从10:13:24发出update语句,到修改完是10:13:27,中间经过了3秒,这期间都是锁定状态,别的会话必须等待,如果修改完后我一直不提交,这些数据块就都是锁定的,此时如果有其他会话来查询这些数据块的内容,那么就要从回滚段里读取前映像数据了,不允许直接查看数据块当前的状态,因为新修改的数据还没有提交,事物还没有结束。
update统计信息里反应出的当前读
12121 db block gets 当前读12121个块,说明锁定了这么多个块
3126 consistent gets 一致性读相对就少很多
小结:这就是undo segment在consistent read和current read方式下的运作机制。
六 示例演示一个导致ora-01555错误的场景
Ora-01555经典中的经典,直到现在Oracle还是没有完美解决,既然oracle使用到了回滚段来保证读一致性,有利必有弊,那么就会有快照太旧的情况发生,我们所查询的前映像被无情的覆盖了。
原因:就是当一个select查询等待时间太长,这个过程中查询的数据被修改完毕commit了,此时它的前映像就为inactive状态,如果这时候有其他会话也想用undo段,就会把inactive状态的回滚区覆盖掉,这时正好select查询完毕想读取它的前映像,发现已经被覆盖了,此时oracle会报ora-01555错误。理解原理很重要
我用一种叫做闪回查询的功能来实现ora-01555
flashback query:原理也是使用undo segment中的前映像,来查询出我们修改之前的数据映像,一般用于误操作恢复。可以基于时间闪回还可以基于SCN号闪回,一秒钟包括好几个SCN号,不管基于什么oracle内部都是按照SCN号顺序操作的。只要我们查找的原映像被覆盖了,就会报ora-01555错误。
实验
LEO1@LEO1> drop table leo3 purge; 清理环境
Table dropped.
LEO1@LEO1> create table leo3 (name varchar2(20),sale number); 创建leo3
Table created.
这个表里记录下面4位小朋友去米国游玩的旅行费
LEO1@LEO1> insert into leo3 values('leonarding',10000);
1 row created.
LEO1@LEO1> insert into leo3 values('sunev_yu',20000);
1 row created.
LEO1@LEO1> insert into leo3 values('alan',30000);
1 row created.
LEO1@LEO1> insert into leo3 values('tigerfish',40000);
1 row created.
LEO1@LEO1> commit;
Commit complete.
看样子tiger最有钱了,跟着tiger走吃喝全都有!
LEO1@LEO1> select * from leo3;
NAME SALE
----------------------------------------------------------
leonarding 10000
sunev_yu 20000
alan 30000
tigerfish 40000
先查一下还没有ship之前的SCN号备用
LEO1@LEO1> select dbms_flashback.get_system_change_number scn from dual;
SCN
-----------------
2595945
由于tiger的慷慨大方包吃包住,我们玩耍的很尽兴!在结束旅行之前大家去银行查一查每个人的cash book
LEO1@LEO1> update leo3 set sale=100 where name='tigerfish';
1 row updated.
LEO1@LEO1> update leo3 set sale=200 where name='alan';
1 row updated.
LEO1@LEO1> update leo3 set sale=300 where name='sunev_yu';
1 row updated.
LEO1@LEO1> update leo3 set sale=400 where name='leonarding';
1 row updated.
LEO1@LEO1> commit;
Commit complete.
哈 发现一个规律现金越少蹭功越强,在此向tigerfish alan两位大师表达敬意!欧巴~阿加西~
LEO1@LEO1> select * from leo3;
NAME SALE
----------------------------------------------------------
leonarding 400
sunev_yu 300
alan 200
tigerfish 100
LEO1@LEO1> select dbms_flashback.get_system_change_number scn from dual;
SCN
----------------
2605429
看SCN:2595945~增长~2605429,记录着数据库所有变化,是持续增长的
这时他们都想看看来时每个人的现金额是多少,花了多少,回去好交差
LEO1@LEO1> select name,sale from leo3 as of scn 2595945;
NAME SALE
----------------------------------------------------------
leonarding 10000
sunev_yu 20000
alan 30000
tigerfish 40000
这些数据,就是从undo segment中读取出来的,我们需要指定当时的SCN号,我们要根据SCN号进行闪回查询。
LEO1@LEO1> alter database datafile '/u01/app/oracle/oradata/LEO1/undotbs02.dbf' autoextend off;
Database altered.
禁用undo表空间自动扩展功能
LEO1@LEO1> select tablespace_name,file_name,autoextensible from dba_data_files where tablespace_name='UNDOTBS2';
TABLESPACE_NAME FILE_NAME AUT
----------------------------------------------------------------------------------------------------------------------------------------------
UNDOTBS2 /u01/app/oracle/oradata/LEO1/undotbs02.dbf NO
我们现在开始覆盖undo segment中的inactive区中前映像,覆盖之后我们再查询时就会出现ora-01555
LEO1@LEO1> begin
for i in 1..100000 loop
update leo3 set sale=10000 where sale>=100;
rollback;
end loop;
end;
/
2 3 4 5 6 7
PL/SQL procedure successfully completed.
经典中的经典出现了ORA-01555
LEO1@LEO1> select name,sale from leo3 as of scn 2595945;
select name,sale from leo3 as of scn 2595945
*
ERROR at line 1:
ORA-01555: snapshot too old: rollback segment number 12 with name "_SYSSMU12_3331027169$" too small
ORA-01555:快照太旧:名为_SYSSMU12_3331027169$的12号回滚段太小,哈~我们成功模拟出undo segment被覆盖场景。
小结:上述实验说明了undo分配是按顺序循环使用,不可跨区覆盖,undo回收也是按顺序循环回收,不可跨区回收。
undo,redo,consistent read,current read,ORA-01555
Oracle undo我们需要掌握什么的更多相关文章
- Oracle undo 镜像数据探究
Oracle undo 镜像数据探究 今天是2013-08-18,隔别一周的 ...
- Oracle undo 表空间管理 (摘DAVID)
Oracle 的Undo有两种方式: 一是使用undo 表空间,二是使用回滚段. 我们通过 undo_management 参数来控制使用哪种方式,如果设为auto,就使用UNDO 表空间,这时必须要 ...
- oracle undo回滚段详解
1.Undo是干嘛用的? 在介绍undo之前先说一下另外一个东西 transaction ,翻译成交易或事务.我们在进行一个事务的过程中需要申请许多资源,一个复杂的事务也需要很多步来完成.那么一个 ...
- Oracle Undo与脏读解析
Undo就是用来记录保存事务操作过程中的数据,如果事务发生错误,可以之前的数据进行填补. Undo segment 是保存在表空间上的.Undo 大小是固定的,既然是固定的也就是有限的.如果保存的记录 ...
- oracle undo 复杂度--oracle核心技术读书笔记四
一. 概述 undo 保存的是旧数据.比方,你改动了一条记录将A列abc改动为def,那么undo里面保存的就是abc.目的有两个:1. 假设你的事务没有提交,可是已经将A列改动,那么别人读取这条数据 ...
- [Oracle]undo表空间使用量为100%
在Toad中发现undo表空间undotbs1使用量已经达到100%,但是奇怪的是数据库并没有hang住,依然可以正常运转 通过Oracle提供的EM查看undotbs1表空间的使用,也达到了78.8 ...
- 转://Oracle undo 自动调优
Oracle 10gr2的后续版本中添加了UNDO信息最短保留时间段自动调优的特性,不再仅仅依据参数UNDO_RETENTION的设定,其调优原则如下:1. 当UNDO TABLESPACE为 fix ...
- 监控和管理Oracle UNDO表空间的使用
对Oracle数据库UNDO表空间的监控和管理是我们日常最重要的工作之一,UNDO表空间通常都是Oracle自动化管理(通过undo_management初始化参数确定):UNDO表空间是用于存储DM ...
- Oracle undo 表空间不可用
由于某次不小心操作,在切换表空间时没有成功,由于把undo的配置参数 undo_management值设置为MANUAL所以在启动数据库时没有报任何错误,但是给表插入数据时报错了,回滚段不可用的错误. ...
随机推荐
- pouchdb-find( pouchdb查询扩展插件 ,便于查询)
pouchdb-find pouchdb-find 环境搭建 下载lib bower install pouchdb-find 引入js <script src="pouchdb.js ...
- 弹出浮层css+JQuery
先来张效果图: HTML代码如下: <body> <div class="bg" id="bg" style="display: n ...
- Dubbo高级特性实践-泛化调用
引言 当后端Java服务用Dubbo协议作为RPC方案的基础,但部分消费方是前端Restful的PHP服务,不能直接调用,于是在中间架设了Router服务提供统一的基于HTTP的后端调用入口. 而Ro ...
- Hadoop启动方式
启动方式 1.逐一启动 hdfs hadoop-daemon.sh start|stop namenode|datanode|secondrynamenode yarn yarn-daemon.sh ...
- MyBatis的关联关系补充 多对多 继承
多对多 一个学生有多个课程 一个课程有多个学生 思路分析 :使用一个中间表 用学生表和课程表的主键作为中间表的联合主键 1数据库表的设计 课程表 学生表 中间表 2/实体类的设计 课程类 public ...
- 【iOS干货】☞ Socket
一.概念 Socket 字面意思又称“套接字” 网络上的两个程序(如,客户端和服务器端)通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 应用程序一般是先通过Socket来建 ...
- java 一款可以与ssm框架完美整合的web报表控件
硕正套件运行于客户端(浏览器),与应用服务器(Application Server)技术无关,所以能完全用于J2EE. ASP.Net.php等技术开发的Web应用产品中. 硕正套件部署于服务器,支持 ...
- nopCommerce 3.9 大波浪系列 之 引擎 NopEngine
本章涉及到的内容如下 1.EngineContext初始化IEngine实例 2.Autofac依赖注入初始化 3.AutoMapper框架初始化 4.启动任务初始化 一.EngineContext初 ...
- documentsUI源码分析
documentsUI源码分析 本文基于Android 6.0的源码,来分析documentsUI模块. 原本基于7.1源码看了两天,但是Android 7.1与6.0中documentsUI模块差异 ...
- Java 9 揭秘(18. Streams API 更新)
Tips 做一个终身学习的人. 在本章中,主要介绍以下内容: 在Stream接口中添加了更加便利的方法来处理流 在Collectors类中添加了新的收集器(collectors) JDK 9中,在St ...