Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2837846
  • 博文数量: 599
  • 博客积分: 16398
  • 博客等级: 上将
  • 技术积分: 6875
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 12:04
个人简介

WINDOWS下的程序员出身,偶尔也写一些linux平台下小程序, 后转行数据库行业,专注于ORACLE和DB2的运维和优化。 同时也是ios移动开发者。欢迎志同道合的朋友一起研究技术。 数据库技术交流群:58308065,23618606

文章分类

全部博文(599)

文章存档

2014年(12)

2013年(56)

2012年(199)

2011年(105)

2010年(128)

2009年(99)

分类: Oracle

2011-08-22 16:15:23

ORACLE数据库闪回可以把整个数据库闪回到过去的某一个时间点。
数据库闪回类似于不完全恢复,但和不完全恢复又有很多区别。
数据库闪回可以恢复数据删除、表删除等用户错误,但是闪回却不能解决物理损坏,譬如文件删除等。
虽然ORACLE的数据库闪回不能解决物理损坏等错误,但有时候可以解决数据库坏块。
当然处理数据库坏块最方便的方法莫过于RMAN的BLOCKRECOVER命令,而且如果闪回日志中不存在相关坏块的前映像的话,
这个方法也行不通了。

有关数据库的闪回配置可以参考metalink 文档 NOTE:ID 249319.1。

以下是一个简单的利用数据库闪回修复坏块的例子:

C:\Documents and Settings\shoupeng.yan>sqlplus test/test

SQL*Plus: Release 10.2.0.1.0 - Production on 星期一 8月 22 14:13:37 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.


连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> SHOW PARAMETER DB_BLOCK_SIZE

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192

SQL> CREATE TABLE T(ID INT,COL1 CHAR(2000),COL2 CHAR(2000),COL3 CHAR(2000));

表已创建。

首先创建表T,定义3个长度是2000的列,BLOC大小K是8K的,为了方便起见,这样每个块只能存放一条记录。

然后往表里插入6条记录:

SQL> INSERT INTO T VALUES(1,RPAD('1',2000,'1'),RPAD('1',2000,'1'),RPAD('1',2000,'1'));

已创建 1 行。

SQL> INSERT INTO T VALUES(2,RPAD('2',2000,'2'),RPAD('2',2000,'2'),RPAD('2',2000,'2'));

已创建 1 行。

SQL> INSERT INTO T VALUES(3,RPAD('3',2000,'3'),RPAD('3',2000,'3'),RPAD('3',2000,'3'));

已创建 1 行。

SQL> INSERT INTO T VALUES(4,RPAD('4',2000,'4'),RPAD('4',2000,'4'),RPAD('4',2000,'4'));

已创建 1 行。

SQL> INSERT INTO T VALUES(5,RPAD('5',2000,'5'),RPAD('5',2000,'5'),RPAD('5',2000,'5'));

已创建 1 行。

SQL> INSERT INTO T VALUES(6,RPAD('6',2000,'6'),RPAD('6',2000,'6'),RPAD('6',2000,'6'));

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> SELECT ID,DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FILE#,
  2         DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCK#
  3  FROM T
  4  ORDER BY ID;

        ID      FILE#     BLOCK#
---------- ---------- ----------
         1          7       1568
         2          7       1564
         3          7       1565
         4          7       1566
         5          7       1567
         6          7       1570

已选择6行。

SQL> CONN / AS SYSDBA
已连接。
SQL> SELECT FLASHBACK_ON,LOG_MODE FROM V$DATABASE;

FLASHBACK_ON       LOG_MODE
------------------ ------------
NO                 ARCHIVELOG

SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。

Total System Global Area           1073741824 bytes
Fixed Size                            1250044 bytes
Variable Size                       746589444 bytes
Database Buffers                    318767104 bytes
Redo Buffers                          7135232 bytes
数据库装载完毕。
SQL> ALTER DATABASE FLASHBACK ON;

数据库已更改。

SQL> ALTER DATABASE OPEN;

数据库已更改。

SQL> SELECT FLASHBACK_ON,LOG_MODE FROM V$DATABASE;

FLASHBACK_ON       LOG_MODE
------------------ ------------
YES                ARCHIVELOG

数据库已经处于闪回状态,这样每当我们修改记录的时候,ORACLE将相关记录的BLOCK复制到闪回日志中。
准备工作已经完成。


我们修改ID=5的记录,这样ORACLE会把ID=5的记录所在的块1567的块复制到闪回日志中。


SQL> ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS';

会话已更改。

SQL> SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER,SYSDATE FROM DUAL;

GET_SYSTEM_CHANGE_NUMBER SYSDATE
------------------------ -------------------
           9063211692914 2011/08/22 15:37:01

SQL> ALTER SYSTEM SWITCH LOGFILE;

系统已更改。

SQL> UPDATE T
  2  SET COL1=RPAD('A',2000,'A')
  3  WHERE ID=5;

已更新 1 行。

SQL> COMMIT;

提交完成。

SQL> ALTER SYSTEM SWITCH LOGFILE;

系统已更改。

SQL>  SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER,SYSDATE FROM DUAL;

GET_SYSTEM_CHANGE_NUMBER SYSDATE
------------------------ -------------------
           9063211692951 2011/08/22 15:38:37

 

用UtralEdit打开数据文件将记录5和6修改,以模拟坏块。


SQL> SELECT TO_CHAR(1567*8192,'XXXXXXXX') FROM DUAL;

TO_CHAR(1
---------
   C3E000

SQL> SELECT TO_CHAR(1568*8192,'XXXXXXXX') FROM DUAL;

TO_CHAR(1
---------
   C40000

根据块号的块大小可以确定记录5位于文件位置的C3E000-C40000之间。

SQL> SELECT TO_CHAR(1570*8192,'XXXXXXXX') FROM DUAL;

TO_CHAR(1
---------
   C44000

SQL> SELECT TO_CHAR(1571*8192,'XXXXXXXX') FROM DUAL;

TO_CHAR(1
---------
   C46000

记录6位于文件位置的C44000-C46000之间。

 关闭数据库修改数据文件,修改完毕打开数据库。

SQL> SHUTDOWN IMMEDIATE
ORA-01031: 权限不足
SQL> CONN / AS SYSDBA
已连接。
SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。

Total System Global Area           1073741824 bytes
Fixed Size                            1250044 bytes
Variable Size                       738200836 bytes
Database Buffers                    327155712 bytes
Redo Buffers                          7135232 bytes
数据库装载完毕。
数据库已经打开。


SQL> CONN TEST/TEST
已连接。
SQL>  SELECT ID FROM T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1567)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'

 

未选定行

SQL>  ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER,LEVEL 10';

会话已更改。

SQL> SELECT ID FROM T ORDER BY ID;

                  ID
--------------------
                   1
                   2
                   3
                   4


设置10231事件可以让ORACLE跳过坏块,可以看到,ID=5和ID=6的记录已经跳过了。

通过DBV也可以看出块1567和1570已经是坏块:

Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.

C:\Documents and Settings\shoupeng.yan>dbv file=C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF

DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 8月 22 15:47:38 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

DBVERIFY - 开始验证: FILE = C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TES
T02.DBF
页 1567 标记为损坏
Corrupt block relative dba: 0x01c0061f (file 7, block 1567)
Bad check value found during dbv:
Data in bad block:
 type: 6 format: 2 rdba: 0x01c0061f
 last change scn: 0x083e.3183738d seq: 0x1 flg: 0x06
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x738d0601
 check value in block header: 0xf345
 computed block checksum: 0xe29b

页 1570 标记为损坏
Corrupt block relative dba: 0x01c00622 (file 7, block 1570)
Bad check value found during dbv:
Data in bad block:
 type: 6 format: 2 rdba: 0x01c00622
 last change scn: 0x083e.318371a6 seq: 0x1 flg: 0x04
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x71a60601
 check value in block header: 0x884
 computed block checksum: 0x301

 

DBVERIFY - 验证完成

检查的页总数: 6400
处理的页总数 (数据): 3212
失败的页总数 (数据): 0
处理的页总数 (索引): 134
失败的页总数 (索引): 0
处理的页总数 (其它): 145
处理的总页数 (段)  : 0
失败的总页数 (段)  : 0
空的页总数: 2907
标记为损坏的总页数: 2
流入的页总数: 0
最高块 SCN            : 830697894 (2110.830697894)

 

 

此时我们将数据库闪回到UPDATE语句后我们记录的那个时间点。

SQL> CONN / AS SYSDBA
已连接。
SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。

Total System Global Area           1073741824 bytes
Fixed Size                            1250044 bytes
Variable Size                       746589444 bytes
Database Buffers                    318767104 bytes
Redo Buffers                          7135232 bytes
数据库装载完毕。
SQL> FLASHBACK DATABASE TO SCN 9063211692951;

闪回完成。

SQL> ALTER DATABASE OPEN READ ONLY;

数据库已更改。

SQL> SELECT ID FROM TEST.T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1570)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'

 

未选定行

SQL>  ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER,LEVEL 10';

会话已更改。

SQL> SELECT ID FROM TEST.T;

                  ID
--------------------
                   2
                   3
                   4
                   5
                   1
                  
可以看到块1567已经修复了,但是块1570没有被修复,这是由于这个BLOCK在闪回日志中不存在,无法覆盖掉原来的坏块。

从DBV的输出中也可以看出块1567已经修复:

C:\Documents and Settings\shoupeng.yan>dbv file=C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF

DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 8月 22 15:57:58 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

DBVERIFY - 开始验证: FILE = C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TES
T02.DBF
页 1570 标记为损坏
Corrupt block relative dba: 0x01c00622 (file 7, block 1570)
Bad check value found during dbv:
Data in bad block:
 type: 6 format: 2 rdba: 0x01c00622
 last change scn: 0x083e.318371a6 seq: 0x1 flg: 0x04
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x71a60601
 check value in block header: 0x884
 computed block checksum: 0x301

 

DBVERIFY - 验证完成

检查的页总数: 6400
处理的页总数 (数据): 3213
失败的页总数 (数据): 0
处理的页总数 (索引): 134
失败的页总数 (索引): 0
处理的页总数 (其它): 145
处理的总页数 (段)  : 0
失败的总页数 (段)  : 0
空的页总数: 2907
标记为损坏的总页数: 1
流入的页总数: 0
最高块 SCN            : 830698378 (2110.830698378)


剩下的工作是将数据库恢复到最新状态。

SQL> SHUTDOWN IMMEDIATE;
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。

Total System Global Area           1073741824 bytes
Fixed Size                            1250044 bytes
Variable Size                       746589444 bytes
Database Buffers                    318767104 bytes
Redo Buffers                          7135232 bytes
数据库装载完毕。
SQL> RECOVER DATABASE;
完成介质恢复。
SQL> ALTER DATABASE OPEN;

数据库已更改。

SQL> SELECT ID FROM TEST.T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1570)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'

 

未选定行

当然数据块1570还是坏块。

    这个只能利用备份来修复了。

SQL> host rman target /

恢复管理器: Release 10.2.0.1.0 - Production on 星期一 8月 22 16:11:14 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

连接到目标数据库: YANSP (DBID=969718535)

RMAN> BLOCKRECOVER DATAFILE 7 BLOCK 1570;

启动 blockrecover 于 22-8月 -11
使用目标数据库控制文件替代恢复目录
分配的通道: ORA_DISK_1
通道 ORA_DISK_1: sid=498 devtype=DISK

通道 ORA_DISK_1: 正在恢复块
通道 ORA_DISK_1: 正在指定要从备份集恢复的块
正在恢复数据文件 00007 的块
通道 ORA_DISK_1: 正在读取备份段 C:\ORACLE_BACKUP\INCREMENT_0JMDMU8R_1_1.BAK
通道 ORA_DISK_1: 已从备份段 1 恢复块
段句柄 = C:\ORACLE_BACKUP\INCREMENT_0JMDMU8R_1_1.BAK 标记 = TAG20110531T1014
通道 ORA_DISK_1: 块恢复完成, 用时: 00:00:03

正在开始介质的恢复
介质恢复完成, 用时: 00:00:15

完成 blockrecover 于 22-8月 -11

RMAN> EXIT


恢复管理器完成。

SQL> SELECT ID FROM TEST.T;

                  ID
--------------------
                   2
                   3
                   4
                   5
                   1
                   6

已选择6行。

 

阅读(1028) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~