“重做”允许Oracle重做事务。“回滚”则允许Oracle撤销或者回滚事务。
重做
重做日志文件是数据库的事务日志,只用来恢复数据库。Oracle有两种类型重做日志文件:在线重做日志和归档重做日志。在线重做日志以循环的方式来写入,当其中一个日志文件写满,就会切换写另外的日志文件,循环往复。归档日至是当在线日志写满的时候,将在线日志拷贝到另外一个地方。
COMMIT
COMMIT语句的执行并不消耗太多时间,而且并不是事务越大COMMIT所消耗的时间越多。实际的情况是,在COMMIT执行之前,Oracle已经完成所要提交事务的大部分工作。
SQL> create table t ( x int );
Table created.
SQL> set serveroutput on
SQL>
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 ( 1 );
7 end loop;
8 commit;
9 dbms_output.put_line
10 ( dbms_utility.get_time-l_start ' hsecs' );
11 end;
12 /
135 hsecs
PL/SQL procedure successfully completed.
SQL>
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 ( 1 );
7 commit;
8 end loop;
9 dbms_output.put_line
10 ( dbms_utility.get_time-l_start ' hsecs' );
11 end;
12 /
161 hsecs
PL/SQL procedure successfully completed.
从上面可以看到,插入多样的数据一次提交比进行多次提交消耗更少的时间。所以,提交的响应时间和事务大小并无太大关系。因为提交之前,Oracle已经完成99%的工作,具体为:
a. 回滚段的纪录已经在SGA中产生。
b. 更改的数据块已经在SGA中产生。
c. 上述两项的缓存的REDO已经在SGA产生。
d. 基于如上三项的的大小以及所消耗时间,上述数据的部分已经写入磁盘。
e. 已经获取所有需要的锁。
那么提交的时候,需要完成如下工作:
a. 为事务产生SCN。
b. LGWR将余下的缓存的重做日志写入磁盘,同时将SCN好记入到重做日志文件。完成这一步之后,事务实际上已经提交。事务实体被移除。在V$TRANSACTION表中找不到事物的相关纪录。
c. Session所持有的锁被释放。
d. 如果被事务所修改的快还在缓存中,那么大多数将被访问以及被“清除”。
真正消耗时间的在于LGWR将重做日志写入磁盘,因为这是物理的I/O访问。但是COMMIT之后,LGWR并不是将所有的 内容写入重做日志。在COMMIT之前,LGWR已经持续的写重做日志。当如下条件满足的时候,LGWR写重做日志:
a. 每三秒
b. 当达到1/3或者1MB大小
c. 当COMMIT的时候
SCN是ORACLE用户保证事务的顺序,确保数据库能被正确恢复。同时,它也用来保证数据库的读一至性以及检查点(checkpointing)。每当事务提交,SCN号增一。
SQL> create table t
2 as
3 select * from all_objects
4 /
Table created.
SQL> insert into t select * from t;
29257 rows created.
SQL> insert into t select * from t;
58514 rows created.
SQL> insert into t select * from t where rownum < 12000;
11999 rows created.
SQL> commit;
Commit complete.
SQL>
SQL> create or replace procedure do_commit( p_rows in number )
2 as
3 l_start number;
4 l_after_redo number;
5 l_before_redo number;
6 begin
7 select v$mystat.value into l_before_redo
8 from v$mystat, v$statname
9 where v$mystat.statistic# = v$statname.statistic#
10 and v$statname.name = 'redo size';
11
12 l_start := dbms_utility.get_time;
13 insert into t select * from t where rownum < name =" 'redo">
SQL> set serveroutput on format wrapped
SQL> begin
2 for i in 1 .. 5
3 loop
4 do_commit( power(10,i) );
5 end loop;
6 end;
7 /
9 rows created
Time to INSERT: .05 seconds
Time to COMMIT: .00 seconds
Generated 1,368 bytes of redo
99 rows created
Time to INSERT: .00 seconds
Time to COMMIT: .00 seconds
Generated 11,596 bytes of redo
999 rows created
Time to INSERT: .03 seconds
Time to COMMIT: .00 seconds
Generated 116,732 bytes of redo
9999 rows created
Time to INSERT: 1.34 seconds
Time to COMMIT: .00 seconds
Generated 1,079,844 bytes of redo
99999 rows created
Time to INSERT: 5.56 seconds
Time to COMMIT: .00 seconds
Generated 11,175,056 bytes of redo
PL/SQL procedure successfully completed.
从上述运行结果可以看到,随着插入数据量的增大,产生的重做日志也逐渐增大,插入所消耗的时间也增多,但是COMMIT所消耗的时间仍然相当的少。所以,也验证了上述结论:在COMMIT之前,ORACLE已经完成了绝大多数的工作,所以COMMIT锁耗用的时间是相当少的。
回滚
将上述程序的COMMIT(23,25行)替换成ROLLBACK,再执行察看回滚所消耗的时间。
Time to INSERT: .04 seconds
Time to ROLLBACK: .00 seconds
Generated 1,504 bytes of redo
99 rows created
Time to INSERT: .00 seconds
Time to ROLLBACK: .00 seconds
Generated 12,288 bytes of redo
999 rows created
Time to INSERT: .03 seconds
Time to ROLLBACK: .00 seconds
Generated 123,736 bytes of redo
9999 rows created
Time to INSERT: .42 seconds
Time to ROLLBACK: .00 seconds
Generated 1,146,652 bytes of redo
99999 rows created
Time to INSERT: 3.99 seconds
Time to ROLLBACK: 1.64 seconds
Generated 11,883,064 bytes of redo
PL/SQL procedure successfully completed.
从上述运行结果可知,与COMMIT不同,随着数据量的增大,回滚所消耗的时间也增加。这是因为回滚是一个消耗时间的操作。
回滚之前,数据库所完成的工作与提交部分(可以参考上述COMMIT部分)相同。
回滚时,ORACLE所需要完成的工作为:
a. 回滚所有的更改。从回滚段中读取数据,并执行与原来相反的操作。例如,如果原来插入一行,回滚时便删除一行。如果更新一行,回滚时候必须更新回去。
b. Session所持有的锁被释放。
测量产生的日志数量
创建如下的一个视图,可以方便的查询系统中的重做日志。
create or replace view redo_size
as
select value
from v$mystat, v$statname
where v$mystat.statistic# = v$statname.statistic#
and v$statname.name = 'redo size';
通过测试脚本,可以看到:通过一条语句更新N行,与通过N条语句来更新N行,所产生的重做日志的数量大致相同。对于删除操作,结果也类似。但对于更新操作,批量更新产生的重做日志更小一些。
还有,如果我们插入2000bytes的行,实际每行产生的重做日志要高于2000bytes。对于删除操作也类似。对于更新操作,将会是2000betys的两倍数量(需要记录数据以及回滚)。
触发器对重做日志的影响:
a. 删除操作的BEFORE和AFTER触发器不会增加额外的重做日志。
b. 插入操作的BEFORE和AFTER触发器都会增加额外的重做日志。
c. 更下操作的BEFORE触发器产生额外重做日志,而AFTER触发器不产生。
d. 行的大小影响插入过程额外重做日志,更新操作不受影响。
能否关闭重做日志
尽量不要关闭重做日志功能,有些语句NOLOGGING因子,但是实际上还是会产生重做日志。这些日志因为记录数据词典更改而产生的。多于NOLOGGING,有如下几点需要注意:
a. 即使使用NOLOGGING,还是会产生少量的重做日志,这用来保护数据词典。
b. NOLOGGING之影响当前操作。例如如果在创建表的语句中使用了NOLOGGING,那么只是在创建表的过程中不产生重做日志。后续对于标的插入删除以及更新还是会产生日志。其他的特殊操作例如INSERT /*+ APPEND */和SQLLDR插入数据不会产生日志。
c. 在以归档模式运行的数据库中,一旦使用NOLOGGING,那么尽快将受影响的文件备份。
待续....
2007年6月25日星期一
2007年6月15日星期五
手工修改spife出现错误
问题:
正在阅读到Expert One on One Oracle,想验证log_buffer的最小值为最大数据块的4倍。打开位于${ORACLE_HOME}/database/ SPFILEORA9I.ORA的数据库参数文件,发现没有对应的参数条目,然后手工增加log_buffer=1,通过服务控制台重新启动数据库。然后通过sql/plus连接,发现不能连接数据库。出现的错误为“ORA- 01034 : ORACLE not available”,“ORA-27101 : shared memory realm does not exist”。Google一下,许多人提到这是因为数据库没有启动。手工启动数据库,相关命令如下:
c:>sqlplus /nolog
sql>conn sys/abcdefg@server as sysdba
sql>startup
而执行如上语句,能够连接数据库,但是startup的时候,系统却报错:“ora-00600,[][][]”。通过“Database Configuration Assistant”进行参数修改的时候,出现同样的错误。
解决方法:
Google一下,原来有人和我犯了同样的错误:Sfile是一个二进制文件,不能通过文本的方式修改。如果需要修改,必须通过“alter system set ... scope=.. ”或者先修改,然后通过“create spfile from pfile;”将pfile里的内容复制到spfile里。 参考:http://www.itpub.net/226670,1.html。
1) 将${ORACLE_HOME}/admin/ora9i/pfile/init.ora.4162007215332文件(这是数据库的pfile参数文件,8i前使用,可以手工编辑)拷贝到${ORACLE_HOME}/database目录下,更名为init.ora。
2) 运行如下命令,使用Pfile参数文件打开数据库。
sqlplus /nolog
conn sys/abcdefg@server as sysdba
startup pfile =${ORACLE_HOME}/databaseinit.ora;
3) 从Pfile重新创建Spfile。create spfile from pfile = 'init.ora';
Spfile相关内容:
找到了eygle关于Spfile的文章(http://www.eygle.com/faq/Oracle9i.New.Feature.Spfile.01.htm)。
1). Oracle通过startup时候,搜索参数文件的顺序:
a.spfile${ORACLE_SID}.ora in (NT: ${ORACLE_HOME}/database)
b.spfile.ora in (NT: ${ORACLE_HOME}/database)
c.init${ORACLESID}.ora in (NT: ${ORACLE_HOME}/database or${ORACLE_HOME}/admindb_name/pfile)
2).修改参数ALTER SYSTEM ,SCOPE参数有三个可选值:MEMORY ,SPFILE , BOTH。
3).查询是否使用了Spfile。
SELECT name,value FROM v$parameter WHERE name='spfile';
SHOW PARAMETER spfile;
SELECT COUNT(*) FROM v$spparameter WHERE value IS NOT NULL;
4).使用Rman备份Spfile。
5).使用Spfile屏蔽或者更改Oracle行为。alter system set event='10841 trace name context forever' scope=spfile;
其他问题。
解决问题的过程中,使用“Startup pfile”命令的时候还出现过“ORA-01031: insufficient privileges upon instance startup”错误。一般检查两个地方,登录系统的O/S用户是否在ORA_DBA用户组中。另为,是否配置${ORACLE_HOME}/network/admin下的sqlnet.ora文件是否存在,以及是否有“SQLNET.AUTHENTICATION_SERVICES = (NTS)”条目,否在Oracle不能使用O/S认证。
正在阅读到Expert One on One Oracle,想验证log_buffer的最小值为最大数据块的4倍。打开位于${ORACLE_HOME}/database/ SPFILEORA9I.ORA的数据库参数文件,发现没有对应的参数条目,然后手工增加log_buffer=1,通过服务控制台重新启动数据库。然后通过sql/plus连接,发现不能连接数据库。出现的错误为“ORA- 01034 : ORACLE not available”,“ORA-27101 : shared memory realm does not exist”。Google一下,许多人提到这是因为数据库没有启动。手工启动数据库,相关命令如下:
c:>sqlplus /nolog
sql>conn sys/abcdefg@server as sysdba
sql>startup
而执行如上语句,能够连接数据库,但是startup的时候,系统却报错:“ora-00600,[][][]”。通过“Database Configuration Assistant”进行参数修改的时候,出现同样的错误。
解决方法:
Google一下,原来有人和我犯了同样的错误:Sfile是一个二进制文件,不能通过文本的方式修改。如果需要修改,必须通过“alter system set ... scope=.. ”或者先修改,然后通过“create spfile from pfile;”将pfile里的内容复制到spfile里。 参考:http://www.itpub.net/226670,1.html。
1) 将${ORACLE_HOME}/admin/ora9i/pfile/init.ora.4162007215332文件(这是数据库的pfile参数文件,8i前使用,可以手工编辑)拷贝到${ORACLE_HOME}/database目录下,更名为init.ora。
2) 运行如下命令,使用Pfile参数文件打开数据库。
sqlplus /nolog
conn sys/abcdefg@server as sysdba
startup pfile =${ORACLE_HOME}/databaseinit.ora;
3) 从Pfile重新创建Spfile。create spfile from pfile = 'init.ora';
Spfile相关内容:
找到了eygle关于Spfile的文章(http://www.eygle.com/faq/Oracle9i.New.Feature.Spfile.01.htm)。
1). Oracle通过startup时候,搜索参数文件的顺序:
a.spfile${ORACLE_SID}.ora in (NT: ${ORACLE_HOME}/database)
b.spfile.ora in (NT: ${ORACLE_HOME}/database)
c.init${ORACLESID}.ora in (NT: ${ORACLE_HOME}/database or${ORACLE_HOME}/admindb_name/pfile)
2).修改参数ALTER SYSTEM ,SCOPE参数有三个可选值:MEMORY ,SPFILE , BOTH。
3).查询是否使用了Spfile。
SELECT name,value FROM v$parameter WHERE name='spfile';
SHOW PARAMETER spfile;
SELECT COUNT(*) FROM v$spparameter WHERE value IS NOT NULL;
4).使用Rman备份Spfile。
5).使用Spfile屏蔽或者更改Oracle行为。alter system set event='10841 trace name context forever' scope=spfile;
其他问题。
解决问题的过程中,使用“Startup pfile”命令的时候还出现过“ORA-01031: insufficient privileges upon instance startup”错误。一般检查两个地方,登录系统的O/S用户是否在ORA_DBA用户组中。另为,是否配置${ORACLE_HOME}/network/admin下的sqlnet.ora文件是否存在,以及是否有“SQLNET.AUTHENTICATION_SERVICES = (NTS)”条目,否在Oracle不能使用O/S认证。
订阅:
博文 (Atom)
