ablog

不器用で落着きのない技術者のメモ

データベースはオンラインのまま一部の表領域を不完全リカバリする

1つのOracleデータベースに複数のシステムのデータが入っていて、あるシステムだけ昨日の夜間バッチが走る前の状態に戻したいといったケースで、関係ない表領域はオンラインのままで一部の表領域だけ巻き戻すことができるか検証してみる。システム単位で表領域が分かれていることを前提とする。


と思って検証しようとしたが、単純にリストア・リカバリではダメだということがわかった。

補助データベース、要するにもう一つデータベースを作って、そこで希望の時点までリカバリして、補助データベースからデータをターゲットデータベースにコピーするといったことになるみたい。ちょっとめんどうだな〜


DB2SQLServer は1インスタンス内に複数のデータベースを作成できるけど、Oracle は1インスタンスに1データベース。1台のマシンで複数のインスタンスを動かすとメモリが大量に必要になるし、こういうケースでは data pump でバックアップとっておいたほうが良さそう。ただし、バックアップとった時点まで戻るし、アーカイブログ使って任意の時点に戻したりすることはできない。

単純に一部の表領域だけ夜間にとったコールドバックアップの時点に戻したい場合は、データファイルのSCNを書き換えてリストア。。。と思ったけど、データベースがオンラインのままだと SCN がどんどん進むから無理か。。。

環境

SQL> !cat /etc/issue
CentOS release 5.3 (Final)
Kernel \r on an \m
SQL> !uname -a
Linux centos51 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0      Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production

検証結果

  • 表領域HIDEBUを作成する。
$ sqlplus / as sysdba
SQL> create tablespace hidebu datafile '/u01/app/oracle/oradata/orcl/hidebu01.dbf' size 5m;
SQL> alter user scott quota unlimited on hidebu;
SQL> select tablespace_name, status from dba_tablespaces;


TABLESPACE_NAME                STATUS
------------------------------ ---------
SYSTEM                         ONLINE
UNDOTBS                        ONLINE
SYSAUX                         ONLINE
TEMP                           ONLINE
USERS                          ONLINE
HIDEBU                         ONLINE
  • コールドバックアップをとる。
SQL> shutdown immediate
SQL> exit
$ cd /u01/app/oracle/oradata/orcl
$ cp -p hidebu01.dbf hidebu01.dbf.org
$ ls -l hidebu*
-rw-r----- 1 oracle oinstall 5251072 1028 21:08 hidebu01.dbf
-rw-r----- 1 oracle oinstall 5251072 1028 21:08 hidebu01.dbf.org
  • データベースをオープンする。
$ sqlplus / as sysdba
SQL> startup
  • USERS表領域とHIDEBU表領域のデータを更新する。
SQL> CREATE TABLE "SCOTT"."EMP1"
   (    "EMPNO" NUMBER(4,0),
        "ENAME" VARCHAR2(10),
        "JOB" VARCHAR2(9),
        "MGR" NUMBER(4,0),
        "HIREDATE" DATE,
        "SAL" NUMBER(7,2),
        "COMM" NUMBER(7,2),
        "DEPTNO" NUMBER(2,0),
         CONSTRAINT "PK_EMP1" PRIMARY KEY ("EMPNO")
	 ) TABLESPACE "USERS"
 /
SQL> CREATE TABLE "SCOTT"."EMP2"
   (    "EMPNO" NUMBER(4,0),
        "ENAME" VARCHAR2(10),
        "JOB" VARCHAR2(9),
        "MGR" NUMBER(4,0),
        "HIREDATE" DATE,
        "SAL" NUMBER(7,2),
        "COMM" NUMBER(7,2),
        "DEPTNO" NUMBER(2,0),
         CONSTRAINT "PK_EMP2" PRIMARY KEY ("EMPNO")
	 ) TABLESPACE "HIDEBU"
/
SQL> select table_name, tablespace_name from dba_tables where owner = 'SCOTT';

TABLE_NAME                     TABLESPACE_NAME
------------------------------ ------------------------------
EMP2                           HIDEBU
EMP1                           USERS

SQL> begin
for i in 1..100 loop
insert into scott.emp1 (empno, ename) values (i,'neo');
end loop;
end;
/
SQL> begin
for i in 1..100 loop
insert into scott.emp2 (empno, ename) values (i,'smith');
end loop;
end;
/
SQL> select count(1) from scott.emp1;

  COUNT(1)
----------
       100

SQL> select count(1) from scott.emp2;

  COUNT(1)
----------
       100

SQL> commit;
  • HIDEBU 表領域を元に戻す。
SQL> alter tablespace hidebu offline;
SQL> !mv hidebu01.dbf hidebu01.dbf.mod
SQL> !cp -p hidebu01.dbf.org hidebu01.dbf
SQL> select FILE#,CHECKPOINT_CHANGE#, LAST_CHANGE# from v$datafile;
     FILE# CHECKPOINT_CHANGE# LAST_CHANGE#
---------- ------------------ ------------
         1             220266
         2             220266
         3             220266
         4             220266
         5             220540       220540

SQL> select scn_to_3timestamp(220540) as timestamp from dual;
--イマココ。うまくいかないので調査中。。。どうやらこの方法では無理だということに気づき、終了〜
SQL> RECOVER TABLESPACE HIDEBU UNTIL TIME '28-OCT-09 10.11.51.000000000 PM28-OCT-09 10.11.51.000000000 PM';
SQL> alter tablespace hidebu online;
SQL> select tablespace_name,status from user_tablespaces;