Oracle非归档模式下插入数据到nologging表和logging表产生的undo信息比较

一首先看我自己的实验环境是处于哪种归档模式:

SQL> select t.LOG_MODE from v$database t;
LOG_MODE
------------
NOARCHIVELOG

二.确定是在非归档模式下之后,我首先创建一个常规的表t_test_nologging

1.建表,所谓常规就是在创建过程中不指定这个表是nologging

SQL> create table t_test_nologging as select * from t_down_log where 1=0;
Table created
SQL> select count(*) from t_down_log;
  COUNT(*)
----------
    660618

2.常规地插入t_test_nologging所有的t_down_log记录
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                         CUR_SIZE_KB
---------------------------------------------------------------- ------------- ------
redo size                    38884.543KB

--插入 t_down_log所有的记录
SQL> insert into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL> commit;
Commit complete
--再次计算undo大小
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                       CUR_SIZE_KB
--------------------------------------------------------------- ------
redo size                  77660.121KB
SQL> select 77660.121 - 38884.543 from dual;
77660.121-38884.543
-------------------
          38775.578

上面插入的方式产生了 38775.578KB的undo


--按照insert append方式插入的时候
SQL> insert /*+ append */ into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL> commit;
Commit complete
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                CUR_SIZE_KB
-----------------------------------------------------
redo size           77771.629KB
SQL> select 77771.629 - 77660.121 from dual;
77771.629-77660.121
-------------------
            111.508
用insert /*+ append */ into 却只产生了111.508KB的undo表空间

可以得出结论,在非归档模式下如果采用 insert /*+ append */ into的方式给非nologging表插入数据的时候产生的undo数据是要少于直接用 insert into方式插入的。



三.在非归档模式下之后,我们将上面创建的那张表设置为nologging表

SQL> alter table t_test_nologging nologging;
Table altered
SQL>
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                当前undo大小(单位KB)
-----------------------------------------
redo size            77773.738KB
SQL> insert into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL> commit;
Commit complete
SQL>
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                        当前undo大小(单位KB)
-----------------------------------------------------------------
redo size                     116393.234KB
SQL> select 116393.234 -  77773.738 || 'KB' from dual;
116393.234-77773.738||'KB'
--------------------------
38619.496KB
SQL> insert /*+ append */ into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL>
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                                                             当前undo大小(单位KB)
---------------------------------------------------------------- ------------------------------------------
redo size                                                        116417.566KB
SQL> commit;
Commit complete
SQL> select 116417.566 - 116393.234 || 'KB' from dual;

116417.566-116393.234||'KB'
---------------------------
24.332KB

上面实验可知尽管我把这张表改为了nologging模式,但还是只能通过 insert /*+ append */ into的方式使得产生的undo减少。

四.直接将 t_test_nologging干掉,然后建立一张新的名字也为 t_test_nologging的nologging表

SQL> drop table t_test_nologging purge;
Table dropped
SQL> create table t_test_nologging nologging as select * from t_down_log where 1 = 0;
Table created
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                            当前undo大小(单位KB)
----------------------------------------------------------------
redo size                        155256.492KB
SQL> insert into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL> commit;
Commit complete
SQL>
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME             当前undo大小(单位KB)
------------------------------- ------------------------------------------
redo size           194108.301KB
SQL> select 194108.301 - 155364.371 || 'KB' from dual;
194108.301-155364.371||'KB'
---------------------------
38743.93KB

--尽管已经是nologging状态的表了,但是在非归档模式下的直接insert时还是会产生大量的redo信息
SQL> truncate table t_test_nologging;
Table truncated
SQL> insert /*+ append */ into t_test_nologging select * from t_down_log;
660618 rows inserted
SQL> commit;
Commit complete

SQL>
SQL> SELECT a.NAME,round(b.VALUE / 1024, 3)||'KB' "当前undo大小(单位KB)"
  2  FROM v$statname a, v$mystat b
  3  WHERE a.statistic# = b.statistic#
  4  AND lower(a.NAME) LIKE '%' || lower('redo size') || '%';
NAME                 当前undo大小(单位KB)
---------------------------------------------------------
redo size             194397.07KB
SQL> select 194397.07 - 194108.301 || 'KB' from dual ;
194397.07-194108.301||'KB'
--------------------------
288.769KB

--处于非归档模式下的unlogging表也只能在insert /*+ append */ into的情况下才能减少undo的产生。


结论:综上实验,对于非归档模式,不管表的状态是nologging还是logging都只能在 insert /*+ append */ into的情况下才能减少undo信息的产生。


--附上查看表是不是logging的sql,以及改变logging方式的sql
SQL> select logging from user_tables where table_name = 'T_TEST_NOLOGGING';
LOGGING
-------
NO
SQL> ALTER TABLE T_TEST_NOLOGGING LOGGING;
Table altered
SQL> select logging from user_tables where table_name = 'T_TEST_NOLOGGING';
LOGGING
-------
YES

但是上面能够成立前提一定得是数据库和表所在的表空间一定是处于no force logging状态
如果是处于force logging的话,那么别说insert /*+ append */ into了,就连建表时指定的nologging都会失效,但是sql*loader这样的工作如果采用直接路径方式会由于跳过了sql引擎,所以不会产生重做数据。

查看数据库是不是force logging状态

SQL> select force_logging from v$database;

FORCE_LOGGING
-------------
NO

修改为force_logging

alter database force logging;

取消force logging

alter database no force logging;

你可能感兴趣的:(Oracle非归档模式下插入数据到nologging表和logging表产生的undo信息比较)