crosscheck backup ORA-19554

朋友在rman中执行crosscheck backup出现ORA-19554错误

RMAN> crosscheck backup;

using channel ORA_DISK_1
released channel: ORA_DISK_1
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of crosscheck command at 01/23/2015 17:23:19
ORA-19554: error allocating device, device type: STB, device name:
ORA-27001: unsupported device type
Additional information: 1

提示找不到STB,根本就没有这种设备,下面执行命令来显示所有配置信息

RMAN> show all;

RMAN configuration parameters are:
CONFIGURE RETENTION POLICY TO REDUNDANCY 1; # default
CONFIGURE BACKUP OPTIMIZATION OFF; # default
CONFIGURE DEFAULT DEVICE TYPE TO DISK; # default
CONFIGURE CONTROLFILE AUTOBACKUP OFF;
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '%F'; # default
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE STB TO '%F'; # default
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE SBT_TAPE TO '%F'; # default
CONFIGURE DEVICE TYPE DISK BACKUP TYPE TO BACKUPSET PARALLELISM 1;
CONFIGURE DEVICE TYPE 'STB' BACKUP TYPE TO COMPRESSED BACKUPSET PARALLELISM 1;
CONFIGURE DEVICE TYPE 'SBT_TAPE' BACKUP TYPE TO BACKUPSET PARALLELISM 1;
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE DISK TO 1; # default
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE STB TO 1; # default
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE SBT_TAPE TO 1; # default
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE DISK TO 1; # default
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE STB TO 1; # default
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE SBT_TAPE TO 1; # default
CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT   '/u02/test_df%t_s%s_s%p';
CONFIGURE MAXSETSIZE TO UNLIMITED; # default
CONFIGURE ENCRYPTION FOR DATABASE OFF; # default
CONFIGURE ENCRYPTION ALGORITHM 'AES128'; # default
CONFIGURE ARCHIVELOG DELETION POLICY TO NONE; # default
CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/u01/app/oracle/10.2.0/db/dbs/snapcf_test.f'; # default

上述信息中有
CONFIGURE DEVICE TYPE ‘SBT_TAPE’ BACKUP TYPE TO BACKUPSET PARALLELISM 1;
说明确实有人设置了SBT_TAPE类型的设备信息,下面将其设置还原为默认值:

RMAN> configure device type 'SBT_TAPE' clear;

old RMAN configuration parameters:
CONFIGURE DEVICE TYPE 'SBT_TAPE' BACKUP TYPE TO BACKUPSET PARALLELISM 1;
RMAN configuration parameters are successfully reset to default value

RMAN> show all;

RMAN configuration parameters are:
CONFIGURE RETENTION POLICY TO REDUNDANCY 1;
CONFIGURE BACKUP OPTIMIZATION OFF;
CONFIGURE DEFAULT DEVICE TYPE TO DISK;
CONFIGURE CONTROLFILE AUTOBACKUP OFF;
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '%F';
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE 'STB' TO '%F';
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE 'SBT_TAPE' TO '%F';
CONFIGURE DEVICE TYPE DISK BACKUP TYPE TO BACKUPSET PARALLELISM 1;
CONFIGURE DEVICE TYPE 'STB' BACKUP TYPE TO COMPRESSED BACKUPSET PARALLELISM 1;
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE DISK TO 1;
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE 'STB' TO 1;
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE 'SBT_TAPE' TO 1;
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE DISK TO 1;
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE 'STB' TO 1;
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE 'SBT_TAPE' TO 1;
CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT   '/u02/test_df%t_s%s_s%p';
CONFIGURE MAXSETSIZE TO UNLIMITED;
CONFIGURE ENCRYPTION FOR DATABASE OFF;
CONFIGURE ENCRYPTION ALGORITHM 'AES128';
CONFIGURE ARCHIVELOG DELETION POLICY TO NONE;
CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/u01/app/oracle/10.2.0/db/dbs/snapcf_test.f';

再来执行crosscheck backup命令正常执行:

RMAN> crosscheck backup;

allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=145 devtype=DISKcrosschecked backup piece: found to be 'AVAILABLE'
backup piece handle=/u02/test_df869734336_s15_s1 recid=5 stamp=869734336
crosschecked backup piece: found to be 'AVAILABLE'
backup piece handle=/u02/test_df869734461_s16_s1 recid=6 stamp=869734463
Crosschecked 2 objects

还原点和闪回数据库

闪回数据库和还原点是两种与数据恢复相关的功能,它们用来替代按时间点恢复来撤消对数据库的改变。闪回数据库能让你将整个数据库进行回滚,使用指定时间窗口来撤消对数据库的改变。这类似于数据库的按时间点恢复。

还原点提供了与闪回数据库相关的能力它是另一种恢复操作。受保护的还原点,在特定的情况下,提供了闪回数据库完整的功能,允许你选择一个SCN并强制要求闪回数据库对这个SCN是可用的。

还原点和闪回数据库可以单独使用也可以一起使用。在这两种情况下,RMAN的flashback database命令或者flashback database语句实际上将数据库还原到一个指定的SCN所对应的状态,例如:

flashback database to restore point ‘before_upgrade’;
flashback databasae to scn 202381;

闪回数据库
闪回数据库,可以通过RMAN的flashback database命令和SQL*Plus的flashback database语句来完成。能够将数据库快速的从逻辑数据错误或用户错误中进行恢复。

它类似于传统的按时间点恢复一样,能够将数据库还原到过去某个时间点的状态。闪回数据库比按时间点恢复来快很多,因为闪回数据库不需要从备份中还原数据文件和从归档重做日志文件中应用相应的改变。

闪回数据库能被用来撤消对数据库不需要的改变。而数据文件完好无损。这包括将数据库还原到之前数据库化身对应的状态。这将撤消open resetlogs操作。

闪回数据库使用它自己的日志机制,它会在闪回区中创建闪回日志。只有在闪回日志是可用时才能使用闪回数据库。因此如果要使用这个功能就必须对数据库进行设置让其创建相关的闪回日志。

为了启用闪回数据库,需要设置闪回区和设置闪回保留策略目标来指定能够将数据库还原到过去某个时间点。

从启用闪回数据库开始,在定期的时间间隔内,数据库将会把每个数据文件中发生改变的数据块复制到闪回日志中。这些数据块镜像以后可用来重构数据文件的内容。

当数据库使用闪回数据库将数据库还原到过去的某些目标时间点时,自从还原时间点开始发生改变的每个数据块将从闪回日志中复制目标时间点对应的数据块。然后应用自数据块被复制到闪回日志时间点开始的重做日志。

注意:在整个时间跨度对于闪回日志相应的重做日志必须都是可用的。

闪回数据库窗口
在一定范围SCN之间有足够的闪回日志数据来支持flashback database命令这就叫闪回数据库窗口。如果闪回区的空间太小,通过设置保留策略当为了给新生成的闪回日志文件分配空间可能会删除过期的闪回日志。根据闪回区的大小,必须被保留的其它备份和需要的闪回日志数据,这可能造成闪回数据库窗口比闪回保留目标的时间要短。

注意:闪回保留目标是一个目标,不是一个绝对受保护能执行闪回数据库的目标。

如果闪回区的大小不能存储为了满足保留策略所需要的闪回日志和其它文件,比如归档重做日志和其它备份。那么为了存储其它文件从最早的SCN开始的闪回日志可能因为空间问题而被删除。

闪回数据库窗口不能对可用闪回日志中的最早SCN进行向前的扩展。闪回日志不能备份到闪回区之外的目录。因此为了增加可用的闪回日志来满足闪回数据窗口,所以要给闪回区可用的最大存储空间。

这里也有一些操作比如删除表空间或收缩数据文件,这些是不能通过闪回数据进行撤消的。在这些操作执行之后,闪回窗口就会立即从这些操作之后重新计算。

如果因为闪回数据库窗口不满足flashback database的要求,按时间点恢复可以最大程度的完成相似的任务。

使用受保护的还原点是唯一能保证你使用闪回数据库能将数据库还原点指定时间点或闪回窗口的方法。

正常还原点
通过指定时间点或SCN来作为还原点的名称来创建还原点,在执行有restore point子句的命令时使用这种标签或别名来指定SCN。

如果可能对你执行的任何操作执行撤消,那么可以创建一个正常的还原点。还原点名称和SCN会被记录到控制文件中。如果后面需要使用闪回数据库,闪回表或按时间点恢复,可以使用还原点名称来指示这个目标时间来代替一个时间表达式或SCN。在可能被撤消的操作执行前定义一个正常的还原点来消除需要手工记录SCN的需要,或在执行闪回查询时查找正确的SCN的需要。

正常还原点是非常轻量级的。控制文件可以包含上千个正常还原点而不会影响数据库的性能。正常还原点最终从控制文件中移除,而不是手工删除,那么它们将不再需要进行维护。

支持还原点的命令
在下面的上下文中还原点用来指定目标SCN:
1.RMAN的recover database和flashback database命令

2.SQL*Plus中的flashback database语句

注意:通常来说,受保护的还原点可以在任何使用正常还原点的操作中作为SCN的别名来使用。除非另有说明,否则正常还原点的使用方法也适用于受保护的还原点。

受保护的还原点
与正常还原点一样,受保护的还原点在恢复操作中也能作为SCN的别名。然而,它们也对闪回数据库提供了特定的功能。

在一个特定的SCN创建一个受保护的还原点可以强制通过执行闪回数据库能将数据库还原到这个SCN所处的状态,即使数据库没有启用闪回日志也能保证。如果闪回日志被启用,创建受保护的还原点强制闪回日志保留策略能满足将数据库闪回到创建受保护还原点后的任意时间点。

受保护还原点能用于将整个数据库还原到一个已知的状态良好的时间点,前提条件是闪回区有足够的空间来存储闪回日志。使用闪回数据库,受nologging操作影响的直接路径插入也能使用受保护的还原点来进行还原操作。

受保护的还原点替代存储快照
在实践中,受保护的还原点能够有效地替代存储快照,它通常用来在一些危险操作之前来保护数据库,比如大范围的更新,应用程序打补丁,或者升级。与创建快照或复制数据库再进行这些操作的相比,可以创建一个受保护的还原点然后执行这些危险操作,只要确只保留必要的闪回日志就行。

闪回数据库和受保护还原点的日志
闪回数据库和受保护还原点的日志是基于在改变应用前被捕获的数据块镜像,因此这些镜像能用来在执行flashback database命令时将数据文件还原到之前时间点所对应的状态。

正常闪回日志和受保护还原点的日志的主要差别就是日志是否会因为闪回区可用空间的压力而被删除。这些差别影响日志可用空间的使用和数据库的性能。

是否对闪回数据库,受保护的还原点启用日志都依赖于你的恢复目标,以及对性能的影响和这些功能对空间的使用。

受保护还原点和闪回区的空间使用
当创建一个受保护的还原点,不管有没有启用完全闪回数据库日志,你都必须监控闪回区可用空间的状态。如果为了满足受保护的还原点而需要的文件是不会满足从闪回区删除的条件。因此,闪回日志的保留策略和为了满足受保护的还的所需要的其它文件,就是满足备份保留策略一样,可能会让闪回区完全被使用掉。

注意:当因为保留策略不能删除任何文件而又遇到空间被使用完的情况时,在许多情况下数据库会被hang住。

闪回日志禁用时受保护还原点日志
如果当闪回数据库日志禁用时创建了受保护的还原点,那么,在受保护还原点创建之后第一次数据文件的数据块更改,在更改之前数据块的镜像会被存储到闪回日志中。闪回日志因此能还原被修改的数据块回到受保护还原点创建时的状态。然而后续对相同数据块的修改不会被记录在日志中,除非在这些修改之前创建另外的受保护还原点。

这种方式的日志有以下重要的影响:
1.可用的块镜像可以在使用flashback database时将数据文件的内容还原到受保护还原点所对应的状态但不能使用flashback database将数据库还原到受保护还原点与当前时间之间的某个时间点。只有当对闪回数据库启用日志才行。如果你需要将数据库还原到一个中间时间点,你只能使用数据库按时间点恢复。

2.因为每个数据块的改变只会被记录一次,当闪回日志被禁用时受保护还原点的日志所使用的空间要比正常闪回日志所使用的空间小。可以按天或周来维护受保护的还原点而不必关注当闪回数据库启用后闪回日志的增长。记录受保护的还原点的日志所产生的性能在禁用闪回数据库日志的情况下影响是很小的。

如果你主要是将数据库还原到受保护还原点所创建的时间点,那么通常关闭闪回数据库日志只使用受保护还原点更有效。例如当正计划在生产数据库服务器上对应用进行升级,在升级开始之前创建一个受保护的还原点,如果升级过程最终失败,可以使用flashback database撤消改变,而不用从备份中进行还原。

使用受保护还原点的闪回数据库日志
如果闪回数据库被启用并且定义了一个或多个受保护的还原点,那么数据库执行正常闪回日志时,会对性能有些影响。根据数据库的工作模式闪回区可能会产生较大的空间压力。然而,不像正常的闪回数据库日志,闪回区总是要保留为了使用flashback database将数据库还原到最早的当前受保护还原点时所需要的闪回日志。闪回日志如果要求满足受保护还原点恢复就不会因为空间压力而被删除。

在这种情况下对于flashback database可以将数据库恢复到闪回窗口中的任意时间点和特定的受保护的还原点所对应的状态,但你必须监控制闪回区的空间使用。

使用正常和受保护还原点

使用受保护还原点的要求
为了支持使用受保护还原点,数据库必须满足下面的要求:
1.compatible参数必须设置为10.2或更高版本

2.数据库必须运行在归档模式下。flashback database操作将数据库还原到受保护的还原点时要求使用一直到还原点以来的归档重做日志。

3.必须设置闪回区.受保护的还原点使用了一种类似于闪回日志的机制,Oracle必须在闪回区存储所要使用的日志

4.如果没有启用闪回数据库,当创建第一个受保护的还原点心(或者如果所有之前创建的受保护的还原点已经被删除后)那么数据库必须处于mount状态,不能是open状态。

注意:在使用正常的还原点没有特殊的要求。

创建正常和受保护还原点
为了创建正常或受保护还原点,使用create restore point语句,并给还原点提供了一个名称并指定它是受保护还原点还是正常还原点(默认值)。

在创建还原点时数据库可以处于open或mount状态。如果是mount状态,那么必须已经完全关闭(物理备库除外)。

下面的命令用来创建一个正常还原点

SQL> create restore point before_truncate;

Restore point created.

下面的命令用来创建一个受保护还原点

SQL> create restore point before_truncate guarantee flashback database;
create restore point before_truncate guarantee flashback database
*
ERROR at line 1:
ORA-38784: Cannot create restore point 'BEFORE_TRUNCATE'.
ORA-38787: Creating the first guaranteed restore point requires mount mode when flashback database is off.

根据错误提示可以看出当数据库没有启用flashback database时想要创建受保护的还原点只能在mount状态下创建。

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> create restore point before_truncate guarantee flashback database;

Restore point created.


SQL> col name for a20
SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
  2  GUARANTEE_FLASHBACK_DATABASE,STORAGE_SIZE
  3  FROM V$RESTORE_POINT;

NAME                        SCN TIME                                DATABASE_INCARNATION# GUARANTEE_FLASHBACK_DATABASE STORAGE_SIZE
-------------------- ---------- ----------------------------------- --------------------- ---------------------------- ------------
BEFORE_TRUNCATE         2849315 27-JAN-15 02.40.56.000000000 PM                         2 YES                          8192000

显示还原点
为了查看当前定义的还原点,可以使用v$restore_point控制文件视图:

SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
GUARANTEE_FLASHBACK_DATABASE,STORAGE_SIZE
FROM V$RESTORE_POINT;

SQL> col name for a20
SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
  2  GUARANTEE_FLASHBACK_DATABASE,STORAGE_SIZE
  3  FROM V$RESTORE_POINT;

NAME                        SCN TIME                                DATABASE_INCARNATION# GUARANTEE_FLASHBACK_DATABASE STORAGE_SIZE
-------------------- ---------- ----------------------------------- --------------------- ---------------------------- ------------
BEFORE_TRUNCATE         2849315 27-JAN-15 02.40.56.000000000 PM                         2 YES                          8192000

可以看到每个还原点的名称,SCN,时间和还原点创建时的数据库对应化身的序列号,是正常还原点还是受保护还原点,以及为了提供足够的信息来支持闪回数据库操作该还原点在闪回区所使用的空间大小。

可以使用只查询受保护的还原点信息:

SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
GUARANTEE_FLASHBACK_DATABASE, STORAGE_SIZE
FROM V$RESTORE_POINT
WHERE GUARANTEE_FLASHBACK_DATABASE='YES';


SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
  2  GUARANTEE_FLASHBACK_DATABASE, STORAGE_SIZE
  3  FROM V$RESTORE_POINT
  4  WHERE GUARANTEE_FLASHBACK_DATABASE='YES';

NAME                        SCN TIME                                                                        DATABASE_INCARNATION# GUARANTEE_FLASHBACK_DATABASE   STORAGE_SIZE
-------------------- ---------- --------------------------------------------------------------------------- --------------------- ------------------------------ ------------
BEFORE_TRUNCATE         2849315 27-JAN-15 02.40.56.000000000 PM                                                                 2 YES                                 8192000

对于正常还原点,storage_size为0。对于受保护的还原点storage_size指示了为了保证能对还原点执行flashback database操作所要保留日志所消耗的闪回区的空间大小。

下面的正常还原点的storage_size确实为0:

SQL> SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
  2  GUARANTEE_FLASHBACK_DATABASE, STORAGE_SIZE
  3  FROM V$RESTORE_POINT
  4  WHERE GUARANTEE_FLASHBACK_DATABASE='YES';

NAME                        SCN TIME                                                                        DATABASE_INCARNATION# GUARANTEE_FLASHBACK_DATABASE   STORAGE_SIZE
-------------------- ---------- --------------------------------------------------------------------------- --------------------- ------------------------------ ------------
BEFORE_TRUNCATE         2849315 27-JAN-15 02.40.56.000000000 PM                                                                 2 YES                                 8192000



SQL> select count(*) from tt;

  COUNT(*)
----------
     51281

SQL> truncate table tt;

Table truncated.

SQL> select count(*) from tt;

  COUNT(*)
----------
         0


SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> select open_mode from v$database;

OPEN_MODE
----------
MOUNTED

SQL>  select  flashback_on from v$database;

FLASHBACK_ON
------------------
RESTORE POINT ONLY

SQL> flashback database to restore point before_truncate;

Flashback complete.



SQL> alter database open;
alter database open
*
ERROR at line 1:
ORA-01589: must use RESETLOGS or NORESETLOGS option for database open


SQL>  alter database open resetlogs;

Database altered.

SQL> select count(*) from tt;

  COUNT(*)
----------
     51281

删除还原点
当不再需要已经存在的还原点时或者想用已经存在的还原点名称来创建一个新的还原点时就可以删除该还原点,下面使用dorp restore point语句还删除还原点:

SQL> drop restore point before_truncate;

Restore point dropped.

drop restore point用于删除正常还原点受保护还原点。

注意:正常还原不管有没有被显式删除最终都会从控制文件中删除。控制文件中还原点保留规则如下:
1.在控制文件中总是会保留最近的2048个还原点
2.只有还原点比比control_file_record_keep_time值所保留的还原点更新,而不管定义还原点的个数

正常还原点只要不满足上述条件就会从控制文件中删除。
受保护还原点从不会因为自动地从控制文件中删除,除非显式删除它们。

监控受保护还原点的空间使用情况
当在数据库中定义受保护还原点后,应该监控为了满足还原点而被存储的相关文件在闪回区中的空间使用情况。可以使用下面的查询语句查看storage_size列来判断每个受保护还原点相关文件的大小。

SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
GUARANTEE_FLASHBACK_DATABASE,STORAGE_SIZE
FROM V$RESTORE_POINT;

为了查看闪回区的使用大小可以查询v$recovery_file_dest和v$flash_recovery_area_usage视图:

SQL> select * from v$recovery_file_dest;

NAME                                                                             SPACE_LIMIT SPACE_USED SPACE_RECLAIMABLE NUMBER_OF_FILES
-------------------------------------------------------------------------------- ----------- ---------- ----------------- ---------------
/u01/app/oracle/flash_recovery_area                                               2147483648    9699328           9699328               1
SQL> select * from v$flash_recovery_area_usage;

FILE_TYPE    PERCENT_SPACE_USED PERCENT_SPACE_RECLAIMABLE NUMBER_OF_FILES
------------ ------------------ ------------------------- ---------------
CONTROLFILE                   0                         0               0
ONLINELOG                     0                         0               0
ARCHIVELOG                    0                         0               0
BACKUPPIECE                   0                         0               0
IMAGECOPY                  0.45                      0.45               1
FLASHBACKLOG                  0                         0               0

Oracle闪回数据库的设置与维护

闪回数据库的限制
因为阀回数据库是用来撤消某一时刻对数据文件所做的改变,因此它有以下限制:
1.闪回数据库只能撤消对数据文件的改变。它不能用于修复介质故障或者对意外删除的数据文件进行恢复。

2.不能使用闪回数据库来撤消对数据文件的收缩操作

3.如果数据库的控制文件从备份中进行了还原或者重新创建了控制文件,那么之前所累积的闪回日志信息将会被废弃。不能使用flashback database将数据库还原到还原控制文件或重新创建控制文件之前的某个时间点。

4.使用闪回数据库还原到某个时间点时,如果在这个时间点数据库正在执行nologging操作,那么在闪回数据库完成之后,受nologging操作影响的对象和数据文件可能存在坏块。例如,如果在2015-01-27的9:00到9:15正在以nologging模式执行直接路径插入操作,而后来你需要使用闪回数据库将数据库还原到2015-01-27的9:07分所对应的状态,那么在闪回数据库操作完成之后,由直接路径插入操作相关的对象和数据文件可有坏块。

如果可能要避免闪回数据库将数据库还原有nologging操作的时间点。也可以在任何nologging操作之后为了确保能恢复到该操作之后某个时间点可以执行全备或增量备份。如果你期望使用闪回数据库将数据库还原到某个操作执行的时间点,比如直接路径插入,可以考虑在logging模式下执行这些操作。

启用闪回数据库的条件
启用闪回数据库需要满足以下条件:
1.数据库必须运行在archivelog模式下,因为在执行闪回数据库操作时需要归档重做日志

2.必须设置闪回区,因为闪回日志只能存储在闪回区中

3.对于RAC环境中的数据库,闪回区必须是可以共享访问的集簇文件系统或者ASM

启用闪回日志
为了对闪回数据库启用闪回日志,要设置db_flashback_retention_target初始化参数并执行alter database flashback on语句。下面是启用闪回日志的过程:
1.确保数据库处于mount状态而不是open状态。例如:

SQL> shutdown immediate

SQL> startup mount

2.可选操作,可以将db_flashback_retention_target参数的值设置为你所期待的闪回窗口以分钟为单位

SQL> ALTER SYSTEM SET DB_FLASHBACK_RETENTION_TARGET=4320; # 3 days

db_flashback_retention_target的默认值是一天(1440分钟)

3.使用v$database.FLASHBACK_ON可以查看闪回日志是否已启用,现在是“NO”,表示尚未启用:

SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
NO
4.对整个数据库启用闪回数据库功能:
SQL> ALTER DATABASE FLASHBACK ON;

从此,在快速恢复区的flashback子目录下将会出现扩展名为.flb的文件,它们就是闪回日志。

SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
YES

闪回数据库命令的语法很简单:在进入MOUNT状态后执行flashback database to scn xxx 或flashback database to timestamp xxx 。

一次闪回数据库操作可能由两种方式进行。比如,令当前时间点为T_C,数据库闪回的目标时间点为T_1(T_C大于T_1),使用的命令为“flashback database to timestamp T_1”,该命令会自动选择以下两种方式的其中一个进行闪回操作。

方式一:

(1)第一阶段:利用闪回日志将数据库从T_C回退至较T_1更旧的某一时刻T_2。
(2)第二阶段:利用重做日志将数据库从T_2前滚至T_1。

方式二:

(1)第一阶段:确定一个比T_1更旧的某一时刻T_2。
(2)第二阶段:对于闪回日志根本无法恢复的对象或数据,把当初此类对象第一次产生的时间为T_3,首先利用T_3到T_2的重做日志将其重新产生并恢复。
(3)第三阶段:利用闪回日志将数据库从T_C回退至T_2。
(4)第四阶段:利用重做日志将数据库从T_2前滚至T_1(途中经过T_2)。

究竟采用哪种方式执行取决于目标时间点T_1与当前时间点T_C之间执行过什么命令,如果是在闪回日志中有对应反向操作的命令(如insert、update、delete)就采用方式一;如果在闪回日志中找不到对应反向操作的命令(比如:truncate命令)则采用方式二。方式二较方式一可能会索要更多的重做日志才可以完成闪回。

比如,若有任何对象发生过截断操作(truncate table xxx),那么方式二中的T3就是当初创建被截断的表的时刻,这意味着整个闪回操作需要从T3至T1的所有的重做日志,否则闪回数据库不可能成功。这样,可能会发生这样的问题:即使只是在10秒前错误地截断了一张表,现需要回到10秒之前,但是闪回数据库时flashback database命令向管理员索要几年前的归档日志!

如果T_1和T_C之间只是发生过类似update那样的DML,若是想回到10秒前,那么会采用方式一,差不多只是需要10秒的闪回日志和归档日志,闪回会很快,这也是闪回的真谛。

无论哪种方式,都可能遇到重做日志不充分的问题,下面来模拟这种情况:

1.检查数据库是否启用了闪回数据库,从下面的查询结果可知当前数据库没有启用闪回数据库

SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
NO

2.创建一个测试表,该表共有51282条记录

SQL> create table jy as select * from dba_objects;

Table created.

SQL> select count(*) from jy;

  COUNT(*)
----------
     51282

3.查询一下当前数据库的SCN号

SQL> SELECT CURRENT_SCN FROM V$DATABASE;

CURRENT_SCN
-----------
    2879920

4.重启数据库并启用闪回数据库

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> alter database flashback on;

Database altered.

SQL> alter database open;

Database altered.

5.向表jy中增加一倍的记录

SQL> insert into jy select * from jy;

51282 rows created.

SQL> commit;

Commit complete.

SQL> select count(*) from jy;

  COUNT(*)
----------
    102564

6.查询当前数据库的SCN号

SQL> SELECT CURRENT_SCN FROM V$DATABASE;

CURRENT_SCN
-----------
    2880218

7.执行闪回数据库,将表jy的记录恢复到只有51282条记录

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.


SQL> flashback database to scn 2879920;
flashback database to scn 2879920
*
ERROR at line 1:
ORA-38754: FLASHBACK DATABASE not started; required redo log is not available
ORA-38762: redo logs needed for SCN 2879811 to SCN 2879920
ORA-38761: redo log sequence 19 in thread 1, incarnation 2 could not be accessed

也可能遇到闪回日志不够的问题,报错信息如下所示:

SQL> flashback database to scn 2879920;
flashback database to scn 2879920
*
ERROR at line 1:
ORA-38729: Not enough flashback database log data to do FLASHBACK.

这里之所以不能闪回到SCN为2879920的时间点,是因为那时数据库没有启用闪回。

8.查看一下v$flashback_database_log视图,检查最远可以回到哪里

SQL> select oldest_flashback_scn,
  2  to_char(oldest_flashback_time,'YYYY-MM-DD HH24:MI:SS')
  3  from v$flashback_database_log;

OLDEST_FLASHBACK_SCN TO_CHAR(OLDEST_FLAS
-------------------- -------------------
             2880101 2015-01-27 23:32:18

从查询结果可以看到数据库最远可以闪回到SCN号为2880101的时间点

9.在MOUNT状态发起闪回操作后,管理员可以反复地以任何顺序执行这3个命令:flashback database to xxx,recover database和alter database open read only

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.

SQL> flashback database to scn 2880210;

Flashback complete.

SQL> alter database open read only;

Database altered.

SQL> select count(*) from jy;

  COUNT(*)
----------
    102564

从上述结果可以看到现在将数据库闪回到SCN为2880210的时间点,表jy的记录数为102564不是我们期待的51282

10.再次将数据库闪回到SCN号为2880150的时间点

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.


SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> flashback database to scn 2880150;

Flashback complete.

SQL> alter database open read only;

Database altered.

SQL> select count(*) from jy;

  COUNT(*)
----------
     51282

从上述结果可以看到将数据库闪回到SCN为2880150的时间点时表jy的记录为51282达到我们期待的结果。

11.完成闪回数据库的最后操作。

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.

SQL> alter database open resetlogs;

Database altered.

SQL>  select count(*) from jy;

  COUNT(*)
----------
     51282


默认情况下对于所有永久表空间都会生成闪回日志。你也可以通过对指定的表空间来禁用闪回日志来减少开销:
SQL> ALTER TABLESPACE users FLASHBACK OFF;

可以使用下面的命令对表空间重新启用闪回日志:
SQL>alter tablespace users flashback on;

注意如果对一个表空间禁用了闪回数据库,那么在执行flashback database之前要确保该表空间的数据文件处于脱机状态。

对整个数据库禁用闪回日志:
SQL>alter database flashback off;

RMAN的改变跟踪

RMAN的改变跟踪
RMAN的改变跟踪功能通过在改变跟踪文件中记录每一个数据文件发生改变的数据块来提高增量备份的性能。如果改变跟踪被启用,RMAN使用改变跟踪文件来标识自上次增量备份以来发生改变的数据块,这样就能避免扫描每个数据文件的所有数据块。

在启用改变跟踪后,第一次level 0级的增量备份仍然会扫描每个数据文件的所有数据块,这时改变跟踪文件不能反应数据块的状态。后续的增量备份将使用level 0级的增量备份作为父备份集这样就可以利用改变跟踪文件来进行增量备份。

使用改变跟踪不会改变执行增量备份的命令,改变跟踪本身在设置后通常需要较少的维护。

改变跟踪默认情况下是禁用的,因为它在数据库的正常操作期间会有一些小的性能开销。然而,为了在备份期间对数据文件执行完全扫描,且在两次备份期间只有少量数据块发生改变时,使用改变跟踪就是很有用的。如果你的备份策略使用增量备份,那么应该启用改变跟踪。

一旦对整个数据库创建了改变跟踪文件,默认情况下改变跟踪文件所生成的目录是由
db_create_file_dest参数来决定的。也可以在启用改变跟踪时指定改变跟踪的文件名和存储目录。

注意:在RAC环境下,为了让所有的节点都能使用改变跟踪文件应该将改变跟踪文件存储在共享存储中

Oracle保存足够的改变跟踪文件能让增量备份使用最近8个增量备份作为它的父备份。

虽然RMAN不支持对改变跟踪文件本身的备份和恢复,如果整修数据库或部分需要还原和恢复,那么恢复对改变跟踪没有影响。在还原和恢复之后,改变跟踪文件会被清除,并再次开始记录数据块的改变。在任何恢复之后下一次的增量备份都能够使用改变跟踪的数据。

启用或禁用块改变跟踪
存储块改变跟踪文件的目录是由db_create_file_dest参数来设置的,下面的语句用来启用块改变跟踪:

SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING;

还可以在启用块改变跟踪时指定块改变跟踪文件创建的目录

SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING
USING FILE '/mydir/rman_change_track.f' REUSE;

REUSE选项告诉Oracle会覆盖已经存在的块跟踪文件

为了禁用块改变跟踪:

SQL> ALTER DATABASE DISABLE BLOCK CHANGE TRACKING;

如果块改变跟踪文件存储在数据库区域,当禁用改变跟踪时会删除。

SQL> alter database enable block change tracking using file '/u01/app/oracle/rman_change_trace.f' reuse;

Database altered.

检查是否生成了改变跟踪文件

[root@oracle11g oracle]# ls -lrt
total 11632
drwxr-xr-x  3 oracle oinstall     4096 Sep  5 08:47 10.2.0
drwxrwxr-x  3 oracle oinstall     4096 Sep  5 09:12 oradata
drwxr-x---  3 oracle oinstall     4096 Sep  5 09:12 admin
drwxrwxr-x  3 oracle oinstall     4096 Sep  5 09:13 flash_recovery_area
-rw-r--r--  1 oracle oinstall   226495 Nov 18 10:55 utlu112i_8.sql
-rw-r--r--  1 oracle oinstall    10373 Nov 18 11:02 upgrade_info.log
drwxr-xr-x  3 root   root         4096 Nov 18 21:00 11.2.0
drwxrwx---  7 oracle oinstall     4096 Nov 18 21:37 oraInventory
drwxrwxr-x 11 oracle oinstall     4096 Nov 18 21:37 diag
drwxr-xr-x  2 oracle oinstall     4096 Nov 18 21:39 checkpoints
drwxr-x---  5 oracle oinstall     4096 Nov 19 18:55 cfgtoollogs
-rw-r--r--  1 oracle oinstall     3261 Nov 23 21:24 upchk.log
-rw-r--r--  1 oracle oinstall     2237 Nov 26 11:55 downgrade.log
-rw-r-----  1 oracle oinstall 11600384 Jan 26 21:32 rman_change_trace.f

禁用块改变跟踪:

SQL> alter database disable block change tracking;

Database altered.

检查是否删除了生成的改变跟踪文件

[root@oracle11g oracle]# ls -lrt
total 284
drwxr-xr-x  3 oracle oinstall   4096 Sep  5 08:47 10.2.0
drwxrwxr-x  3 oracle oinstall   4096 Sep  5 09:12 oradata
drwxr-x---  3 oracle oinstall   4096 Sep  5 09:12 admin
drwxrwxr-x  3 oracle oinstall   4096 Sep  5 09:13 flash_recovery_area
-rw-r--r--  1 oracle oinstall 226495 Nov 18 10:55 utlu112i_8.sql
-rw-r--r--  1 oracle oinstall  10373 Nov 18 11:02 upgrade_info.log
drwxr-xr-x  3 root   root       4096 Nov 18 21:00 11.2.0
drwxrwx---  7 oracle oinstall   4096 Nov 18 21:37 oraInventory
drwxrwxr-x 11 oracle oinstall   4096 Nov 18 21:37 diag
drwxr-xr-x  2 oracle oinstall   4096 Nov 18 21:39 checkpoints
drwxr-x---  5 oracle oinstall   4096 Nov 19 18:55 cfgtoollogs
-rw-r--r--  1 oracle oinstall   3261 Nov 23 21:24 upchk.log
-rw-r--r--  1 oracle oinstall   2237 Nov 26 11:55 downgrade.log

SQL> select filename from v$block_change_tracking;

FILENAME
——————————————————————————–
/u01/app/oracle/rman_change_trace.f

2.关闭数据库.

SQL> shutdown immediate

Database closed.
Database dismounted.
ORACLE instance shut down.

3.使用操作系统命令将块改变跟踪文件移动到新的位置

[root@oracle11g oracle]# mv rman_change_trace.f rman_change_trace_new.f

4.mount数据库,更改块改变跟踪文件

SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> alter database rename file '/u01/app/oracle/rman_change_trace.f' to '/u01/app/oracle/rman_change_trace_new.f';

Database altered.

5.打开数据库

SQL> alter database open;

Database altered.

SQL> alter database disable block change tracking;

Database altered.

[root@oracle11g oracle]# ls -lrt
total 284
drwxr-xr-x  3 oracle oinstall   4096 Sep  5 08:47 10.2.0
drwxrwxr-x  3 oracle oinstall   4096 Sep  5 09:12 oradata
drwxr-x---  3 oracle oinstall   4096 Sep  5 09:12 admin
drwxrwxr-x  3 oracle oinstall   4096 Sep  5 09:13 flash_recovery_area
-rw-r--r--  1 oracle oinstall 226495 Nov 18 10:55 utlu112i_8.sql
-rw-r--r--  1 oracle oinstall  10373 Nov 18 11:02 upgrade_info.log
drwxr-xr-x  3 root   root       4096 Nov 18 21:00 11.2.0
drwxrwx---  7 oracle oinstall   4096 Nov 18 21:37 oraInventory
drwxrwxr-x 11 oracle oinstall   4096 Nov 18 21:37 diag
drwxr-xr-x  2 oracle oinstall   4096 Nov 18 21:39 checkpoints
drwxr-x---  5 oracle oinstall   4096 Nov 19 18:55 cfgtoollogs
-rw-r--r--  1 oracle oinstall   3261 Nov 23 21:24 upchk.log
-rw-r--r--  1 oracle oinstall   2237 Nov 26 11:55 downgrade.log

如果不能关闭数据库,那么你必须禁用改变跟踪,再在重新启用时指定新的目录。例如:

ALTER DATABASE DISABLE BLOCK CHANGE TRACKING;
ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING FILE 'new_location';

如果你选择使用这种方法,将会丢失改变跟踪文件中的内容。直到你下次完成level 0级的增量备份之前,RMAN将不得不扫描整个文件

评估改变跟踪文件的大小
改变跟踪文件的大小与数据库的大小和重做日志线程数成正比。它的大小不与数据库的频繁更新相关。通常来说块改变跟踪所需要的空间大小是将被跟踪的数据块大小的1/30000。注意,然而下面的两种原因可能会让改变跟踪文件比评估的大小大很多:
1.为了避免随着数据库的增长而要给改变跟踪文件分配空间所产生的开销,改变跟踪文件一开始创建时就是10M,并且以10M的大小来增加。因此对于任何大小接近300G的数据库来说,改变跟踪文件的大小不小于10M,对于大小接近600G的数据库来说,改变跟踪文件的大小不小于20M,依此类推。

2.对于每个数据文件,不管改变跟踪文件有多大都会在改变跟踪文件中将分配320K的空间。因此,如果有大量的小数据文件,改变跟踪文件将会比包含同样数据量的少量的大数据文件对应的改变跟踪文件大

乱用Hint造成性能问题案例二

某医保系统在业务高峰期间相关模块使用不了查询不出结果,生成业务高峰期间上午10点到11点期间的AWR报告
1

2

从上面的top sql部分可以看到执行时间最长的已经达到19019秒,还有几个运行时间也要执行几千秒,其中SQLID为d7bv3q1camq5x的SQL逻辑读和物理读都上几千万甚至上亿次。而每次也就返回200多行记录。
3

4

其中SQL语句为:

select /*+ rule */
 a.stat_type,
 a.his_item_code,
 a.his_item_name,
 a.item_code,
 max((select count(*)
       from mt_fee_fin aa
      where a.hospital_id = aa.hospital_id
        and a.serial_no = aa.serial_no
        and a.item_code = aa.item_code)) as item_sn,
 a.item_name,
 a.medi_item_type,
 a.price,
 sum(a.dosage) as dosage,
 a.model,
 replace(a.standard, '  ', '') as standard,
 sum(a.money) as money,
 sum(nvl(d.audit_money, 0)) as audit_money,
 d.hosp_reason_staff as hosp_reason_staff,
 d.hosp_reason_date as hosp_reason_date,
 d.hosp_reason_staffid as hosp_reason_staffid,
 d.hosp_reason as hosp_reason,
 d.center_resualt as center_resualt,
 d.center_flag as center_flag,
 d.audit_reason_id as audit_reason_id,
 sum(nvl(b.all_cash, 0)) as all_cash,
 (case
   when a.medi_item_type = '0' then
    (SELECT bo_flag
       FROM bs_item
      WHERE bs_item.item_code = a.item_code
        AND ROWNUM < 2)
   else
    (SELECT bo_flag
       FROM bs_medi
      WHERE bs_medi.medi_code = a.item_code
        AND ROWNUM < 2)
 end) as bo_flag,
 sum(nvl(b.part_cash, 0)) as part_cash,
 decode(nvl(d.audit_reason_id, 0),
        0,
        d.audit_reason,
        '%%' || to_char(d.audit_reason_id) || '%%') as audit_reason
  from mt_fee_fin a,
       pm_account_biz c,
       pm_fee_audit d,
       (select hospital_id,
               serial_no,
               policy_item_code,
               serial_fee,
               fee_batch,
               SUM(decode(fund_id,
                          '999',
                          decode(b.label_flag, '101', real_pay, 0),
                          '003',
                          decode(label_flag, '101', real_pay, 0),
                          0)) AS all_cash,
               SUM(decode(fund_id,
                          '999',
                          decode(b.label_flag, '102', real_pay, 0),
                          '003',
                          decode(label_flag, '102', real_pay, 0),
                          0)) AS part_cash
          from mt_pay_record_fin b
         where b.hospital_id = '4307210003'
           and b.serial_no = '25735455'
           and serial_fee <> 0
           and valid_flag = '1'
         group by hospital_id,
                  serial_no,
                  policy_item_code,
                  serial_fee,
                  fee_batch) b
 where a.hospital_id = c.hospital_id
   and a.serial_no = c.serial_no
   and a.hospital_id = '4307210003'
   and a.serial_no = '25735455'
   and a.hospital_id = b.hospital_id(+)
   and a.serial_fee = b.serial_fee(+)
   and a.serial_no = b.serial_no(+)
   and a.fee_batch = b.fee_batch(+)
   and a.valid_flag = '1'
   and c.valid_flag = '1'
   and d.audit_staff_id(+) = 2103
   and d.AUDIT_PHASE(+) = '1'
   and d.serial_fee(+) <> 0
   and a.serial_fee = d.serial_fee(+)
   and d.account_id(+) = 16905170
   and c.account_id = 16905170
 group by a.stat_type,
          a.item_name,
          a.his_item_name,
          a.price,
          a.his_item_code,
          a.item_code,
          a.medi_item_type,
          a.model,
          a.standard,
          d.hosp_reason,
          d.center_resualt,
          d.center_flag,
          d.hosp_reason_staff,
          d.hosp_reason_date,
          d.hosp_reason_staffid,
          d.audit_reason_id,
          d.audit_reason
 Order By a.stat_type, a.item_name, a.his_item_name

在程序的SQL语句使用了/*+ rule */提示,就会让优化器使用RBO,不使用CBO。 这样使得优化器少了许多选择CBO高效执行计划的机会。当我们去掉/*+ rule */,使用CBO时其执行结果如下:

SQL> select 
  2   a.stat_type,
  3   a.his_item_code,
  4   a.his_item_name,
  5   a.item_code,
  6   max((select count(*)
  7         from mt_fee_fin aa
  8        where a.hospital_id = aa.hospital_id
  9          and a.serial_no = aa.serial_no
 10          and a.item_code = aa.item_code)) as item_sn,
 11   a.item_name,
 12   a.medi_item_type,
 13   a.price,
 14   sum(a.dosage) as dosage,
 15   a.model,
 16   replace(a.standard, '  ', '') as standard,
 17   sum(a.money) as money,
 18   sum(nvl(d.audit_money, 0)) as audit_money,
 19   d.hosp_reason_staff as hosp_reason_staff,
 20   d.hosp_reason_date as hosp_reason_date,
 21   d.hosp_reason_staffid as hosp_reason_staffid,
 22   d.hosp_reason as hosp_reason,
 23   d.center_resualt as center_resualt,
 24   d.center_flag as center_flag,
 25   d.audit_reason_id as audit_reason_id,
 26   sum(nvl(b.all_cash, 0)) as all_cash,
 27   (case
 28     when a.medi_item_type = '0' then
 29      (SELECT bo_flag
 30         FROM bs_item
 31        WHERE bs_item.item_code = a.item_code
 32          AND ROWNUM < 2)
 33     else
 34      (SELECT bo_flag
 35         FROM bs_medi
 36        WHERE bs_medi.medi_code = a.item_code
 37          AND ROWNUM < 2)
 38   end) as bo_flag,
 39   sum(nvl(b.part_cash, 0)) as part_cash,
 40   decode(nvl(d.audit_reason_id, 0),
 41          0,
 42          d.audit_reason,
 43          '%%' || to_char(d.audit_reason_id) || '%%') as audit_reason
 44    from mt_fee_fin a,
 45         pm_account_biz c,
 46         pm_fee_audit d,
 47         (select hospital_id,
 48                 serial_no,
 49                 policy_item_code,
 50                 serial_fee,
 51                 fee_batch,
 52                 SUM(decode(fund_id,
 53                            '999',
 54                            decode(b.label_flag, '101', real_pay, 0),
 55                            '003',
 56                            decode(label_flag, '101', real_pay, 0),
 57                            0)) AS all_cash,
 58                 SUM(decode(fund_id,
 59                            '999',
 60                            decode(b.label_flag, '102', real_pay, 0),
 61                            '003',
 62                            decode(label_flag, '102', real_pay, 0),
 63                            0)) AS part_cash
 64            from mt_pay_record_fin b
 65           where b.hospital_id = '4307210003'
 66             and b.serial_no = '25735455'
 67             and serial_fee <> 0
 68             and valid_flag = '1'
 69           group by hospital_id,
 70                    serial_no,
 71                    policy_item_code,
 72                    serial_fee,
 73                    fee_batch) b
 74   where a.hospital_id = c.hospital_id
 75     and a.serial_no = c.serial_no
 76     and a.hospital_id = '4307210003'
 77     and a.serial_no = '25735455'
 78     and a.hospital_id = b.hospital_id(+)
 79     and a.serial_fee = b.serial_fee(+)
 80     and a.serial_no = b.serial_no(+)
 81     and a.fee_batch = b.fee_batch(+)
 82     and a.valid_flag = '1'
 83     and c.valid_flag = '1'
 84     and d.audit_staff_id(+) = 2103
 85     and d.AUDIT_PHASE(+) = '1'
 86     and d.serial_fee(+) <> 0
 87     and a.serial_fee = d.serial_fee(+)
 88     and d.account_id(+) = 16905170
 89     and c.account_id = 16905170
 90   group by a.stat_type,
 91            a.item_name,
 92            a.his_item_name,
 93            a.price,
 94            a.his_item_code,
 95            a.item_code,
 96            a.medi_item_type,
 97            a.model,
 98            a.standard,
 99            d.hosp_reason,
100            d.center_resualt,
101            d.center_flag,
102            d.hosp_reason_staff,
103            d.hosp_reason_date,
104            d.hosp_reason_staffid,
105            d.audit_reason_id,
106            d.audit_reason
107   Order By a.stat_type, a.item_name, a.his_item_name
108  ;
....省略...

277 rows selected.

Elapsed: 00:00:00.05

Execution Plan
----------------------------------------------------------
Plan hash value: 1363767461

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                         |     1 |   338 |     7  (43)| 00:00:01 |
|   1 |  SORT AGGREGATE                 |                         |     1 |    36 |            |          |
|*  2 |   TABLE ACCESS BY INDEX ROWID   | MT_FEE_FIN              |     1 |    36 |     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN             | PK_MT_FEE_FIN           |     1 |       |     1   (0)| 00:00:01 |
|*  4 |  COUNT STOPKEY                  |                         |       |       |            |          |
|   5 |   TABLE ACCESS BY INDEX ROWID   | BS_ITEM                 |    12 |   192 |     3   (0)| 00:00:01 |
|*  6 |    INDEX RANGE SCAN             | IDX_ITEM_CODE           |    12 |       |     1   (0)| 00:00:01 |
|*  7 |   COUNT STOPKEY                 |                         |       |       |            |          |
|   8 |    TABLE ACCESS BY INDEX ROWID  | BS_MEDI                 |    12 |   216 |     3   (0)| 00:00:01 |
|*  9 |     INDEX RANGE SCAN            | IDX_MEDI_CODE           |    12 |       |     1   (0)| 00:00:01 |
|  10 |  SORT GROUP BY                  |                         |     1 |   338 |     7  (43)| 00:00:01 |
|* 11 |   HASH JOIN OUTER               |                         |     1 |   338 |     6  (34)| 00:00:01 |
|  12 |    NESTED LOOPS OUTER           |                         |     1 |   283 |     3   (0)| 00:00:01 |
|  13 |     NESTED LOOPS                |                         |     1 |   139 |     2   (0)| 00:00:01 |
|* 14 |      TABLE ACCESS BY INDEX ROWID| PM_ACCOUNT_BIZ          |     1 |    29 |     1   (0)| 00:00:01 |
|* 15 |       INDEX UNIQUE SCAN         | PK_PM_ACCOUNT_BIZ       |     1 |       |     1   (0)| 00:00:01 |
|* 16 |      TABLE ACCESS BY INDEX ROWID| MT_FEE_FIN              |     1 |   110 |     1   (0)| 00:00:01 |
|* 17 |       INDEX RANGE SCAN          | PK_MT_FEE_FIN           |     1 |       |     1   (0)| 00:00:01 |
|  18 |     TABLE ACCESS BY INDEX ROWID | PM_FEE_AUDIT            |     1 |   144 |     1   (0)| 00:00:01 |
|* 19 |      INDEX RANGE SCAN           | PK_PM_FEE_AUDIT         |     1 |       |     1   (0)| 00:00:01 |
|  20 |    VIEW                         |                         |     1 |    55 |     2  (50)| 00:00:01 |
|  21 |     HASH GROUP BY               |                         |     1 |    57 |     2  (50)| 00:00:01 |
|* 22 |      TABLE ACCESS BY INDEX ROWID| MT_PAY_RECORD_FIN       |     1 |    57 |     1   (0)| 00:00:01 |
|* 23 |       INDEX RANGE SCAN          | IDX_MT_PAY_RECORD_FIN_2 |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("AA"."ITEM_CODE"=:B1)
   3 - access("AA"."HOSPITAL_ID"=:B1 AND "AA"."SERIAL_NO"=:B2)
   4 - filter(ROWNUM<2)
   6 - access("BS_ITEM"."ITEM_CODE"=:B1)
   7 - filter(ROWNUM<2)
   9 - access("BS_MEDI"."MEDI_CODE"=:B1)
  11 - access("A"."HOSPITAL_ID"="B"."HOSPITAL_ID"(+) AND "A"."SERIAL_FEE"="B"."SERIAL_FEE"(+) AND
              "A"."SERIAL_NO"="B"."SERIAL_NO"(+) AND "A"."FEE_BATCH"="B"."FEE_BATCH"(+))
  14 - filter("C"."SERIAL_NO"='25735455' AND "C"."HOSPITAL_ID"='4307210003' AND
              "C"."VALID_FLAG"='1')
  15 - access("C"."ACCOUNT_ID"=16905170)
  16 - filter("A"."VALID_FLAG"='1')
  17 - access("A"."HOSPITAL_ID"='4307210003' AND "A"."SERIAL_NO"='25735455')
  19 - access("D"."ACCOUNT_ID"(+)=16905170 AND "D"."AUDIT_PHASE"(+)='1' AND
              "A"."SERIAL_FEE"="D"."SERIAL_FEE"(+))
       filter(TO_NUMBER("D"."AUDIT_STAFF_ID"(+))=2103 AND "D"."SERIAL_FEE"(+)<>0 AND
              "D"."AUDIT_PHASE"(+)='1' AND "A"."SERIAL_FEE"="D"."SERIAL_FEE"(+))
  22 - filter("SERIAL_FEE"<>0 AND "VALID_FLAG"='1')
  23 - access("B"."HOSPITAL_ID"='4307210003' AND "B"."SERIAL_NO"='25735455')


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
       1247  consistent gets
         12  physical reads
          0  redo size
       9160  bytes sent via SQL*Net to client
       2220  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         227  rows processed

其中逻辑读为1247,物理读12,比起几千万上亿次,提高了上万倍。

后面经检查发现在这套系统中,有大理SQL使用了/*+ rule */ Hint,最好的处理方法是修改SQL代码,这里为了应急我使用了_optimizer_ignore_hints参数让优化器忽略所有的hint。

闪回与归档参数的设置

Oracle闪回技术提供了一组功能用来查看数据的过去状态并且支持数据按时间返回到之前的状态不用对数据库从备份中执行大量的还原操作或者执行按时间点恢复。在大部分情况下闪回功能非常有效破坏性比介质恢复小。

Oracle的大部分闪回功能是在逻辑层面进行操作,查看和维护数据库对象,比如:
Oracle 闪回查询:指定目标时间对数据库运行查询来查看在指定时间点的数据结果。为了从一个不想要生效的改变中对表进行恢复,用户可以选择错误之前的时间并运行查询来检索丢失或改变的记录。

Oracle闪回版本查询:能查看在指定时间间隔内一个或多个表中已经存在记录的所有版本。还可以检索行记录不同版本的元数据,包括开始时间,结束时间,操作和创建这个版本的事务ID。这个功能可以用来恢复丢失的数据和查看表的改变。

Oracle闪回事务查询:能查看由单个事务所产生的改变或者在一个时间周期内所有事务的改变。

Oracle闪回表:将一个表返回到之前某个时间点的状态。当数据库处于联机状态时也能还原表数据。只撤消特定表的改变。

Oracle闪回删除:是dorp table的反操作

闪回表,闪回查询,闪回事务查询和闪回版本查询都依赖于undo数据,记录对Oracle数据库每一个更新的影响。undo的主要作用主要是用于SQL查询的一致性读与事务的回滚,这些undo信息包括了重构过去时间点数据所需要的信息。

闪回删除是建立在回收站机制上的,Oracle会将删除的数据库对象保留到因为要分配新空间而不得不覆盖原来使用的空间为止。

注意:逻辑层面的闪回功能不依赖于RMAN。

在物理层面,Oracle闪回数据库提供了一种对数据库执行按时间点恢复的替代方法。如果数据文件已经包含了所不期待的改变,那么使用闪回数据库能使用当前的数据文件将它的内容还原到过去时间点所处的状态。而结果就是按时间点恢复一样,但其操作速度更快因为它不需要从备份中还原数据文件,比介质恢复应用的重做要少很多。

闪回数据库使用闪回日志来访问数据块的之前版本,它的一些信息与归档重做日志一样。闪回数据库要求你对数据库设置了闪回区,因为闪回日志只能存储在这里。闪回日志缺省情况下是没启用的。闪回日志所使用的空间由数据库自动管理,在闪回区会让空间使用保持平衡。

注意:闪回数据库被集成到RMAN中,在执行闪回数据库时可以自动从备份中检索的任何归档重做日志,它也能使用SQL*Plus来执行,但在这种情况下你必须保证它所要应用的归档日志都在磁盘上。

如果闪回区没有分配足够的空间,那么闪回日志因为备份和归档日志文件可能会被删除。数据库按时间点恢复可以达到与闪回数据库同样的效果,将数据库的内容返回到过去的时间点。

Oracle数据库有联机重做日志,这个日志是记录对数据库所做的修改,比如插入,删除,更新数据等,对这些操作都会记录在联机重做日志里。一般数据库至少要有2个联机重做日志组。当一个联机重做日志组被写满的时候,就会发生日志切换,这时联机重做日志组2成为当前使用的日志,当联机重做日志组2写满的时候,又会发生日志切换,去写联机重做日志组1,就这样反复进行。

如果数据库处于非归档模式,联机日志在切换时就会丢弃. 而在归档模式下,当发生日志切换的时候,被切换的日志会进行归档。比如,当前在使用联机重做日志1,当1写满的时候,发生日志切换,开始写联机重做日志2,这时联机重做日志1的内容会被拷贝到另外一个指定的目录下。这个目录叫做归档目录,拷贝的文件叫归档重做日志。

数据库使用归档方式运行时才可以进行灾难性恢复。
1.归档日志模式和非归档日志模式的区别
非归档模式只能做冷备份,并且恢复时只能做完全备份.最近一次完全备份到系统出错期间的数据不能恢复.
归档模式可以做热备份,并且可以做增量备份,可以做部分恢复.
用ARCHIVE LOG LIST 可以查看当前模式状态是归档模式还是非归档模式.

当前数据库没有启动归档

SQL> archive log list
Database log mode              No Archive Mode
Automatic archival             Disabled
Archive destination            USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     191
Current log sequence           193

从上面的信息可以知道归档目标为USE_DB_RECOVERY_FILE_DEST,这说归档日志将会存储到闪回区这里之所以归档目录为是因为当没有设置其它归档目录时log_archive_dest_10会隐式的使用USE_DB_RECOVERY_FILE_DEST来存储归档重做日志

SQL> show parameter log_archive_dest

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest                     string
log_archive_dest_1                   string
log_archive_dest_10                  string
log_archive_dest_2                   string
log_archive_dest_3                   string
log_archive_dest_4                   string
log_archive_dest_5                   string
log_archive_dest_6                   string
log_archive_dest_7                   string
log_archive_dest_8                   string
log_archive_dest_9                   string
log_archive_dest_state_1             string      enable
log_archive_dest_state_10            string      enable
log_archive_dest_state_2             string      enable
log_archive_dest_state_3             string      enable
log_archive_dest_state_4             string      enable
log_archive_dest_state_5             string      enable
log_archive_dest_state_6             string      enable
log_archive_dest_state_7             string      enable
log_archive_dest_state_8             string      enable
log_archive_dest_state_9             string      enable

从上面的信息可以看到当前数据库没有设置任何归档目录,下面来设置归档目录

SQL> alter system set log_archive_dest_1='location=/u02' scope=both;

System altered.

再来查看归档重做日志存储的目录

SQL> archive log list
Database log mode              No Archive Mode
Automatic archival             Disabled
Archive destination            /u02
Oldest online log sequence     191
Current log sequence           193

可以看到现在数据库显示的归档日志目录为我们所指定的/u02

下面来启用闪回

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  327155712 bytes
Fixed Size                  1273516 bytes
Variable Size             138412372 bytes
Database Buffers          184549376 bytes
Redo Buffers                2920448 bytes
Database mounted.
SQL> archive log list
Database log mode              No Archive Mode
Automatic archival             Disabled
Archive destination            /u02
Oldest online log sequence     191
Current log sequence           193

SQL> show parameter db_recovery_file

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_recovery_file_dest                string      /u01/app/oracle/flash_recovery
                                                 _area
db_recovery_file_dest_size           big integer 2G

SQL> alter database force logging;

Database altered.


SQL> alter database flashback on;
alter database flashback on
*
ERROR at line 1:
ORA-38706: Cannot turn on FLASHBACK DATABASE logging.
ORA-38707: Media recovery is not enabled.

现在虽然我们设置了db_recovery_file_dest与db_recovery_file_dest_size,强制数据库记录日志,但数据库没有启用归档是不能雇用闪回的,下面启用归档。

SQL> alter database archivelog;

Database altered.

再次启用闪回

SQL> alter database flashback on;

Database altered.

当启用闪回就不能使用log_archive_dest与log_archive_duplex_dest参数来指定归档日志目录。而是必须使用log_archive_dest_n

SQL> alter system set log_archive_dest='location=/u01' scope=both;
alter system set log_archive_dest='location=/u01' scope=both
*
ERROR at line 1:
ORA-02097: parameter cannot be modified because specified value is invalid
ORA-16018: cannot use LOG_ARCHIVE_DEST with LOG_ARCHIVE_DEST_n or
DB_RECOVERY_FILE_DEST


SQL> alter system set log_archive_duplex_dest='location=/u01' scope=both;
alter system set log_archive_duplex_dest='location=/u01' scope=both
*
ERROR at line 1:
ORA-02097: parameter cannot be modified because specified value is invalid
ORA-16018: cannot use LOG_ARCHIVE_DUPLEX_DEST with LOG_ARCHIVE_DEST_n or
DB_RECOVERY_FILE_DEST

从上面的错误信息确实可以看到当启用闪回后确实不能使用log_archive_dest与log_archive_duplex_dest参数来指定归档日志目录

Proudly powered by WordPress | Indrajeet by Sus Hill.