共计 3488 个字符,预计需要花费 9 分钟才能阅读完成。
Oracle 补全日志 (Supplemental logging) 特性因其作用的不同可分为以下几种:最小(Minimal), 支持所有字段(all), 支持主键(primary key), 支持唯一键(unique), 支持外键(foreign key)。包括 LONG,LOB,LONG RAW 及集合等字段类型均无法利用补全日志。
最小 (Minimal) 补全日志开启后可以使得 logmnr 工具支持链式行,簇表和索引组织表。可以通过以下 SQL 检查最小补全日志是否已经开启:
SELECT supplemental_log_data_min FROM v$database;
若结果返回 YES 或 IMPLICIT 则说明已开启最小补全日志,当使用 ALL,PRIMARY,UNIQUE 或 FOREIGN 补全日志时最小补全日志默认开启(即检查结果为 IMPLICIT)。
一般情况下我们在使用逻辑备库时启用主键和惟一键的补全日志,而有时表上可能没有主键,惟一键或唯一索引;我们通过以下实验总结这种情况下 Oracle 的表现。
首先建立相关的测试表:
alter database add supplemental log data (primary key,unique index) columns ;
create table test (t1 int , t2 int ,t3 int ,t4 int);
alter table test add constraint pk_t1 primary key (t1); –添加主键
随后使用循环插入一定量的数据
update test set t2=10; commit; — 更新数据
使用 LOGMNR 工具分析之前的操作,可以看到 REDO 中记录的 SQL 形式如下:
update“SYS”.”TEST”set“T2”=’10’where“T1”=’64’and“T2”=’65’and ROWID =‘AAAMiSAABAAAOhiAA/’;
其中 where 字句后分别记录了主键值,被修改字段的值和原行的 ROWID。
现在我们将原表上的主键去掉来观察。
alter table test drop constraint pk_t1 ;
update test set t2=11; commit; — 更新数据
使用 LOGMNR 分析可以发现,REDO 中的 SQL 记录如下:
update“SYS”.”TEST”set“T2”=’11’where“T1”=‘1’and“T2”=’10’and“T3”=‘3’and“T4”=‘4’and ROWID =‘AAAMiSAABAAAOhiAAA’;
当没有主键的情况下,where 子句后记录了所有列值和 ROWID。
以下实验在存在唯一索引情况下的表现
create unique index pk_t1 on test(t1);
update test set t2=15; commit;
使用 LOGMNR 分析可以发现,REDO 中的 SQL 记录如下:
update“SYS”.”TEST”set“T2”=’15’where“T1”=‘9’and“T2”=’11’and“T3”=’11’and“T4”=’12’and ROWID =‘AAAMiSAABAAAOhiAAI’;
以上是 t1 列有唯一索引但不限定 not null 的情况,下面我们加上 not null 限制
alter table test modify t1 not null;
update test set t2=21; commit;
使用 LOGMNR 分析可以发现,REDO 中的 SQL 记录如下:
update“SYS”.”TEST”set“T2”=’21’where“T1”=‘2’and“T2”=’15’and ROWID =‘AAAMiSAABAAAOhiAAB’;
如以上 SQL 所示,在存在唯一索引的情况下 where 子句后仍记录了所有列和 ROWID; 在存在唯一索引和非空约束的情况下表现与存在主键的情况一致。
当某个表上的列数量较多时且没有主键或唯一索引和非空约束的情况下,开启补全日志可能导致重做日志总量大幅提高。
首先建立一个存在 250 列的表:
Drop table test;
create table test (
t1 varchar2(5),
t2 varchar2(5),
t3 varchar2(5),
t4 varchar2(5), …t250 varchar2(5))
insert into test values (‘TEST’,’TEST’……); commit; –将 255 个列填入数据
alter database drop supplemental log data (primary key,unique index) columns; –关闭补全日志
set autotrace on;
update test set t2=’BZZZZ’where t1=’TEST’; commit;
可以从自动跟踪信息中看到,本条更新产生了 516 的重做量。
alter database add supplemental log data (primary key,unique index) columns;–重新开启补全日志
update test set t2=’FSDSD’where t1=’TEST’;
跟踪信息显示产生了 3044 的重做量。
补全日志因作用域的不同又可分为数据库级的和表级的。表级补全日志又可以分为有条件的和无条件的。有条件限制的表级补全日志仅在特定列被更新时才会起作用,有条件限制的表级补全日志较少使用,这里我们不做讨论。
下面我们来观察无条件限制表级补全日志的具体表现:
alter database drop supplemental log data (primary key,unique index) columns;
alter table test add supplemental log data (primary key,unique index) columns;
update test set t2=’ZZZZZ’; commit;
使用 LOGMNR 工具查看 redo 中的 SQL:
update“SYS”.”TEST”set“T2”=‘ZZZZZ’where“T1”=‘TEST’and“T2”=‘AAAAA’and“T3”=‘TEST’………
可以发现 where 子句之后包含了所有列值。
delete test; commit;
使用 LOGMNR 工具查看 redo 中的 SQL:
delete from“SYS”.”TEST”where“T1”=‘TEST’and“T2”=‘ZZZZZ’and“T3”=‘TEST’and“T4”=‘TEST’and“T5”……
delete 操作同样在 where 子句之后包含了所有列值。
又我们可以针对表上字段建立特定的补全日志组,以减少 where 子句后列值的出现。
alter table test drop supplemental log data (primary key,unique index) columns; –关闭表上原先的补全日志
alter table test add supplemental log group test_lgp (t1 ,t2,t3,t4,t5,t6,t12,t250) always; –创建补全日志组
update test set t2=’XXXXX’; commit;
使用 LOGMNR 工具查看 redo 中的 SQL:
update“SYS”.”TEST”set“T2”=‘XXXXX’where“T1”=‘TEST’and“T2”=‘TEST’and“T3”=‘TEST’and“T4”=‘TEST’and“T5”=‘TEST’and“T6”=‘TEST’and“T12”=‘TEST’and“T250”=‘TEST’and ROWID =‘AAAMieAABAAAOhnAAA’;
如上所示重做日志中正确地显示了 UPDATE 操作中用户指定的字段值。
delete test;
使用 LOGMNR 工具查看 redo 中的 SQL:
delete from“SYS”.”TEST”where“T1”=‘TEST’and“T2”=‘XXXXX’and“T3”=‘TEST’……
delete 操作在重做日志中仍然保留了所有列值。
针对字段较多的表,我们在能够以多个列保证数据唯一性且非空的情况下 (即应用概念上的主键) 来指定表上的补全日志组,以减少 update 操作时所产生的重做日志,而对于 delete 操作则无法有效改善。
更多 Oracle 相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138989.htm