oracle commit 和 rollback
来源:互联网 发布:女鞋原单淘宝推荐 编辑:程序博客网 时间:2024/05/21 09:32
先来看看有关redo的东西:
redo 向量被记录在redo 日志文件中,oracle使用日志文件的目的就是介质错误时,可以恢复数据库 。oracle有两种日志文件,分别是在线日志文件和归档日志文件。每个数据库至少还有两组日志文件,当其中一个日志文件写满时,oracle就会切换到下一个日志文件继续写,此时,当日志再次写满时,如果oracle没有启用归档日志,oracle会直接覆盖原来的日志文件,再次写入1号日志文件。如果oracle启用了归档日志,oracle会先将1号日志写入归档日志,再写入日志。以下是oracle官方文档的一些解释,在这就不翻译了
Redo entries record data that you can use to reconstruct all changes made to the database, including the undo segments. Therefore, the redo log also protects rollback data. When you recover the database using redo data, the database reads the change vectors in the redo records and applies the changes to the relevant blocks.
Redo records are buffered in a circular fashion in the redo log buffer of the SGA and are written to one of the redo log files by the Log Writer (LGWR) database background process. Whenever a transaction is committed, LGWR writes the transaction redo records from the redo log buffer of the SGA to a redo log file, and assigns a system change number (SCN) to identify the redo records for each committed transaction. Only when all redo records associated with a given transaction are safely on disk in the online logs is the user process notified that the transaction has been committed.
Redo records can also be written to a redo log file before the corresponding transaction is committed. If the redo log buffer fills, or another transaction commits, LGWR flushes all of the redo log entries in the redo log buffer to a redo log file, even though some redo records may not be committed. If necessary, the database can roll back these changes.
有关commit的一些事情:
不管事务的大小是多少,commit是一个非常快速的动作。有时候我们以为一个非常大的事务在commit的时候的会非常的慢。很多开发人员认为commit一个小的事务会比提交一个大的事务要占用更少的系统的资源,但是实际上这种做法是在增加系统资源的消耗。在适合的时候提交事务(比如说事务已经全部完成),你不仅提高性能,而且可以减少共享资源的争用(日志文件,很多内部的latch等等)。下面来看一个有关的例子:
SQL> create table t (x int); 表已创建。 SQL> set serveroutput onSQL> DECLARE 2 l_start number default dbms_utility.get_time; 3 BEGIN 4 for i in 1..10000 5 loop 6 INSERT INTO t VALUES(i); 7 end loop; 8 COMMIT; 9 dbms_output.put_line( dbms_utility.get_time-l_start || ' hsecs' ); 10 END; 11 / 32 hsecs
SQL> DECLARE 2 l_start number default dbms_utility.get_time; 3 BEGIN 4 for i in 1..10000 5 loop 6 INSERT INTO t VALUES(i); 7 COMMIT; 8 end loop; 9 dbms_output.put_line( dbms_utility.get_time-l_start || ' hsecs' ); 10 END; 11 / 67 hsecs PL/SQL 过程已成功完成。
我们可以看到不断的提交事务,耗用的时间要比事务完成后在提交要大的的多,所以说不用使用频繁的提交来减少系统资源的争用。
但是,为什么commit会非常的迅速,因为在commit之前oracle已经完成了99%的工作,而commit要做的事非常的少。以下这些就是oracle在commit之前已经完成的:
在SGA中生存回滚段记录
在SGA中生成已经修改的数据块
在SGA中生成上述两条记录的重做日志记录
根据上述记录的大小,一些上述的记录的组合会被刷到磁盘上
得到所有相关的锁
当我们发出commit命令时,oracle做了以下的一些事情
对当前事务生成一个scn号
LGWR将剩余的日志信息刷到磁盘上, transaction entry会被移除,V$TRANSACTION中的相关的记录会消失
释放的所有的的锁资源。
所有修改的BUFFER CACHE中的数据块会被标为clean,也就是说其它事务可以覆盖这个数据块中的内容。
所以通过以上,可以看到,commit要做的事情并不多。其中最长的操作就是执行LGWR将日志刷到磁盘上。但是,LGWR占用的时间也非常的有限,事实上,在提交之前,重做日志的大多数已经被循环的刷到磁盘上了,这样就可以避免提交事务因为刷redo到磁盘上而消耗很多的时间。当redo满足以下条件时,oracle会刷出redo到磁盘上:
每隔3秒中
当redo达到buffer的三分之一时
发出commit命令之后。
我们来看一个例子,来证明commit是一个很平滑的操作
SQL> create table t as select * from all_objects; 表已创建。
SQL> insert into t select * from t; 已创建74429行。 SQL> insert into t select * from t; 已创建148858行。 SQL> commit;
CREATE OR REPLACE PROCEDURE DO_COMMIT(P_ROWS IN NUMBER) AS L_START NUMBER; L_AFTER_REDO NUMBER; L_BEFORE_REDO NUMBER; BEGIN SELECT V$MYSTAT.VALUE INTO L_BEFORE_REDO FROM V$MYSTAT, V$STATNAME WHERE V$MYSTAT.STATISTIC# = V$STATNAME.STATISTIC# AND V$STATNAME.NAME = 'redo size'; L_START := DBMS_UTILITY.GET_TIME; INSERT INTO T SELECT * FROM T WHERE ROWNUM < P_ROWS; DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows created'); DBMS_OUTPUT.PUT_LINE('Time to INSERT: ' || TO_CHAR(ROUND((DBMS_UTILITY.GET_TIME - L_START) / 100,5),'999.99') || ' seconds'); L_START := DBMS_UTILITY.GET_TIME; COMMIT; DBMS_OUTPUT.PUT_LINE('Time to COMMIT: ' || TO_CHAR(ROUND((DBMS_UTILITY.GET_TIME - L_START) / 100,5),'999.99') || ' seconds'); SELECT V$MYSTAT.VALUE INTO L_AFTER_REDO FROM V$MYSTAT, V$STATNAME WHERE V$MYSTAT.STATISTIC# = V$STATNAME.STATISTIC# AND V$STATNAME.NAME = 'redo size'; DBMS_OUTPUT.PUT_LINE('Generated ' ||TO_CHAR(L_AFTER_REDO - L_BEFORE_REDO,'999,999,999,999') || ' bytes of redo'); DBMS_OUTPUT.NEW_LINE; END;
现在我们调用上述过程:
SQL> BEGIN 2 FOR I IN 1 .. 5 LOOP 3 DO_COMMIT(POWER(10, I)); 4 END LOOP; 5 END 6 ; 7 / 9 rows created Time to INSERT: 3.45 seconds Time to COMMIT: .00 seconds Generated 2,484 bytes of redo 99 rows created Time to INSERT: .03 seconds Time to COMMIT: .00 seconds Generated 9,356 bytes of redo 999 rows created Time to INSERT: .24 seconds Time to COMMIT: .00 seconds Generated 103,336 bytes of redo 9999 rows created Time to INSERT: 1.15 seconds Time to COMMIT: .00 seconds Generated 1,052,000 bytes of redo 99999 rows created Time to INSERT: 6.31 seconds Time to COMMIT: .00 seconds Generated 11,500,372 bytes of redo PL/SQL 过程已成功完成。
SQL> show parameter log_buffer; NAME TYPE VALUE ------------------------------------ ----------- --------------- log_buffer integer 8593408
可以看到,不管事务生成的redo多大,commit用的时间总是很短,当redo达到cache的三分之一时,lgwr会在后台将redo刷到磁盘上,所以当提交时,剩下的redo不是很多,所以说redo对commit的影响是很小的。
有关rollback的一些东西:
就上面的这个案例,假如我们把commit换成rollback又会是怎么样的了:
9 rows created Time to INSERT: .00 seconds Time to ROLLBACK: .00 seconds Generated 1,384 bytes of redo 99 rows created Time to INSERT: .00 seconds Time to ROLLBACK: .00 seconds Generated 9,768 bytes of redo 999 rows created Time to INSERT: .03 seconds Time to ROLLBACK: .00 seconds Generated 108,052 bytes of redo 9999 rows created Time to INSERT: .09 seconds Time to ROLLBACK: .02 seconds Generated 1,106,744 bytes of redo 99999 rows created Time to INSERT: .87 seconds Time to ROLLBACK: .03 seconds Generated 12,208,564 bytes of redo PL/SQL 过程已成功完成。
所以可以看到,事务的大小对rollback的影响还是比较大的,原因在于oracle要完成恢复rollback之前的所有工作,让数据库恢复到一个一致的状态 。rollback 之后oracle要完成以下的一些操作:
读取undo段的信息,对之前所有操作做逆操作,比如说执行了insert,那么此时就要执行delete。
释放所有的锁。
可以看出rollback是个很消耗数据库资源的事情,所以在oracle中一般不要在比较大的事务中使用rollback。
- oracle commit 和 rollback
- oracle中的commit和rollback
- Oracle commit和rollback处理
- oracle数据库中commit和rollback命令
- Oracle数据库中commit和rollback命令
- oracle 事务处理 commit rollback
- COMMIT和ROLLBACK
- commit和rollback
- commit和rollback
- mysql commit和rollback
- 【转】Oracle数据库中commit和rollback命令
- Oracle存储过程的commit和rollback,sqlerrm
- ORACLE COMMIT以及ROLLBACK机制
- PB中的Commit和RollBack
- PB中的Commit和RollBack
- JDBC的commit和rollback
- COMMIT和ROLLBACK的用法
- MYSQL的COMMIT和ROLLBACK
- Invocation of init method failed; nested exception is javax.naming.CommunicationException [Root exce
- c++ string 内存分配
- Matlab关于相位相关用于图像配准
- 论软件配置管理中人的因素
- MOSS 2007基础:部署自定义WebPart
- oracle commit 和 rollback
- Linux下Fork与Exec使用
- 思维导图工具MindManager与项目管理(一)
- 编译IOS下的FFMpeg
- 一分钟内掌握较复杂sql
- 在用Android WebView调用js时方法错误
- TOJ 1837 HDU 1385 ZOJ 1456 Minimum Transport Cost / 最短路径
- 自定义UIActionSheet
- 如何做好配置管理 配置管理的三大误区