一.逻辑Standby的准备工作
1确认操作的对象和语句是否能被逻辑Standby支持
由于逻辑Standby是通过SQL应用来保持与Primary数据库的同步。SQL应用与REDO应用是有很大的区别,REDO应用实际上是在物理Standby端进行RECOVER;SQL应用则是分析重做日志文件中的REDO信息,并将其转换为SQL语句,在逻辑Standby端执行,因此,需要注意以下几点:
(1)并非所有的数据类型都能被逻辑Standby支持,
逻辑Standby支持的数据类型有:
BINARY_DOUBLE、BINARY_FLOAT、BLOB、CHAR、CLOBandNCLOB、DATE、INTERVALYEARTOMONTH、INTERVALDAYTOSECOND、LONG、LONGRAW、NCHAR、NUMBER、NVARCHAR2、RAW、TIMESTAMP、
TIMESTAMPWITHLOCALTIMEZONE、TIMESTAMPWITHTIMEZONE、VARCHAR2andVARCHAR
说明:下列类型在获取Standby支持时需要注意兼容性:
CLOB,需要Primary数据库的兼容级别运行于10.1或更高。
含LOB字段的索引组织表(IOT),需要Primary数据库的兼容级别运行于10.2或更高。
不含LOB字段的索引组织表(IOT),需要Primary数据库的兼容级别运行于10.1或更高。
不支持的数据类型有:
BFILE、EncryptedColumns、ROWID,UROWID、XMLType、对象类型、VARRAYS、嵌套表、自定义类型。
也可以通过查询DBA_LOGSTDBY_UNSUPPORTED来确定主数据库中是否含有不支持的对象
SQL>select*fromdba_logstdby_unsupported;
注意:该视图的ATTRIBUTES列,显示对象不被SQL应用支持的原因。
(2)并非所有的存储类型都能被逻辑Standby支持。
逻辑Standby能够支持簇表(ClusterTables)、索引组织表(Index-OrganizedTables)、堆组织表(Heap-OrganizedTables),但不支持段压缩(SegmentCompression)存储类型。
(3)并非所有的PL/SQL包都能被SQL应用支持。
通常那些不会修改系统元数据(Metadata)的Package在实际应用时不会有问题,如DBMS_OUTPUT、DBMS_RANDOM、DBMS_METADATA之类的包。
那些可能修改系统元数据的Package不会被SQL应用支持,即使它们在Primary执行过,并且被成功传输到逻辑Standby端,也不会执行。如DBMS_JAVA、DBMS_REGISTRY、DBMS_ALERT、DBMS_SPACE_ADMIN、DBMS_REFRESH、DBMS_REDEFINITION、DBMS_SCHEDULER及DBMS_AQ等。只有DBMS_JOB例外,Primary数据库的jobs会被复制到逻辑Standby,不过在逻辑Standby数据库不会执行这些job。
说明:元数据,直接理解成对象的物理定义。举例来说,对于某表而言,元数据就是表结构,或表的存储属性等。
(4)并非所有的SQL语句都能在逻辑Standby端执行。
在默认情况下,下列SQL语句在逻辑Standby端会被SQL应用自动跳过:
ALTERDATABASE。
ALTERMATERIALIZEDVIEW。
ALTERMATERIALIZEDVIEWLOG。
ALTERSESSION。
ALTERSYSTEM。
CREATECONTROLFILE。
CREATEDATABASE。
CREATEDATABASELINK。
CREATEPFILEFROMSPFILE。
CREATEMATERIALIZEDVIEW。
CREATEMATERIALIZEDVIEWLOG。
CREATESCHEMAAUTHORIZATION。
CREATESPFILEFROMPFILE。
DROPDATABASELINK。
DROPMATERIALIZEDVIEW。
DROPMATERIALIZEDVIEWLOG。
EXPLAIN。
LOCKTABLE。
SETCONSTRAINTS。
SETROLE。
SETTRANSACTION。
另外,由于SQL语句非常灵活,即使是那些能被SQL应用支持的DDL语句,可能在附加了某些特别的参数后,也不会在逻辑Standby端执行,由于数目较多,此处不再一一列举,感兴趣的话请查阅官方文档。
(5)并非所有的DML操作都能在逻辑Standby端实面SQL应用。
维护逻辑Standby与Primary的数据库同步是通过SQL应用实现,SQL应用转换的SQL语句在执行时,对于INSERT还好说,对于UPDATE、DELETE操作则必须能够唯一定位到数据库待更新的那条记录。问题就在这里,如果Primary库中表设置不当,可能就无法确认唯一条件。
你可能会说可以通过ROWID唯一嘛!千万要谨记啊,逻辑Standby,为啥叫逻辑Standby,就是因为它只是逻辑上与Primary数据库相同,物理上可能与Primary数据库存在相当大差异。一定要认识到,逻辑Standby的物理结构与Primary是不相同的(即使初始逻辑Standby是通过Primary的备份创建)。
因此想通过ROWID更新显然是不好使的,当然也就不能再将其作为唯一条件。下面来看这个问题。
2确保Primary库中各表的行可被唯一标识
Oracle通过主键、唯一索引/约束的补充日志(SupplementalLogging)来确定待更新逻辑Standby数据库中的行。当数据库启用了补充日志,每一条UPDATE语句写REDO的时候会附加列值唯一信息,比如:
如果表定义了主键,则主键列会随同被更新列一起作为UPDATE语句的一部分,以便执行时区分哪些列应该被更新。
如果没有主键,则非空的唯一索引/约束会随同被更新列作为UPDATE语句的一部分,以便执行时区分哪些列应该被更新,如果该表有多个唯一索引/约束,则Oracle自动选择长度最短的那个,以降低生成的重做日志大小。
如果表既无主键,也没有定义唯一索引/约束,所有可定长度的列,连同被更新列同时作为UPDATE语句的一部分。更明确些,可定长度的列是指除LONG、LOB、LONGRAW、OBJECTTYPE、COLLECTION类型外的列。
Oracle建议你为表创建一个主键或非空的唯一索引/约束,以尽可能确保SQL应用能够有效应用REDO数据,更新逻辑Standby数据库。
下列语句可以用来检查SQL应用能否唯一识别表列,并找出不被支持的表:
SQL>SELECTOWNER,TABLE_NAMEFROMDBA_LOGSTDBY_NOT_UNIQUEWHERE(OWNER,TABLE_N
AME)NOTIN(SELECTDISTINCTOWNER,TABLE_NAMEFROMDBA_LOGSTDBY_UNSUPPORTED)
ANDBAD_COLUMN='Y';
OWNERTABLE_NAME
--------------------
TSMSYSRS$
提示:关于DBA_LOGSTDBY_NOT_UNIQUE,该视图显示所有既没主键也没唯一索引的表。如果表中的列包括足够多的信息,通常也可支持在逻辑Standby端的更新,不被支持的表通常是由于列的定义包含了不支持的数据类型。
注意BAD_COLUMN列值,该列有两个值:
Y:表示该表中有采用大数据类型的字段,比如LONG、CLOB。如果表中除LOG列某些行记录完全匹配,则该表无法成功应用于逻辑Standby。Standby会尝试维护这些表,不过你必须保证应用不允许。
N:表示该表拥有足够的信息,能够支持在逻辑Standby的更新,不过仍然建议你为该表创建一个主键或者唯一索引/约束,以提高LOG应用效率。
假设在某张表中你可以确认数据是唯一的,但是基于效率方面的考虑,不想为其创建主键或唯一约束,怎么办呢?没关系,Oracle早想到了这一点,你可以创建一个DISABLE的Primary-KeyRely约束:
提示:关于Primary-KeyRely约束。
如果DBA能够确认表中的行是唯一的,那么可以为该表创建Rely的主键,Rely约束并不会造成系统维护主键的开销,如你对一个表创建了RELY约束,系统则会假定该表中的行是唯一的,这样能够提高SQL应用时的性能。但是需要注意,由于Rely的主键约束只是假定唯一,如果实际并不唯一的话,有可能会造成错误的更新哟。
创建Rely的主键约束非常简单,只要在标准的创建语句后加上RELYDISABLE即可,例如:
SQL>ALTERTABLEUSERADDPRIMARYKEY(ID)RELYDISABLE;
表已更改。
注意:创建了Rely约束后,Oracle会假定该列是唯一的(给DBA足够的信任),不过并不会对该列的值进行唯一性的验证,因此该列是否唯一只能由DBA来主动维护。
二.逻辑Standby创建时的操作步骤
1创建物理Standby
创建逻辑Standby数据库的第一步就是先创建一个物理Standby数据库,然后再将其转换成逻辑Standby数据库。在将其转换为逻辑Standby前,可以随时启动REDO应用,不过一旦决定将其转换为逻辑Standby,就必须先停止该物理Standby的REDO应用,以避免提前应用含LogMiner字典的REDO数据,造成转换为逻辑Standby后,SQL应用时LogMiner字典数据不足而影响到逻辑Standby与Primary的正常同步。
2设置Primary数据库
在创建物理Standby数据库时曾经设置过相关数量的初始化参数,用于Primary数据库与物理Standby的角色切换,对于逻辑Standby的角色切换,那些参数同样好使。
不过注意,如果希望Primary数据库能够正常切换为逻辑Standby角色,那么DBA在配置环境时,还需要设置相应的LOG_ARCHIVE_DEST_n初始化参数,并注意该参数的VALID_FOR属性值需要更改成STANDBY_LOGFILES,STANDBY_ROLE。
完成对初始化参数的配置后,必须在Primary数据库端生成LogMiner字典信息,例如:
SQL>EXECUTEDBMS_LOGSTDBY.BUILD;
提示:本步必须执行,并且执行本步操作时,准逻辑Standby数据库要停止REDO应用。
该过程专门用于生成记录的元数据信息到重做日志文件,逻辑Standby未来正是通过这些元数据保持与Primary数据库的同步。
提示:该过程会自动启用Primary数据库的补充日志(SupplementalLogging)功能(如果未启用的话)。
该过程需要等待当前所有事务完成后才能执行,因此如果当前有较长的事务运行,可能该过程的执行也需要多花一些等待时间。
该过程是通过闪回查询的方式来获取数据字典的一致性,因此Oracle初始化参数UNDO_RETENTION值不能太小,建议设置为3600,并且UNDO表空间也要有足够的空间。
3转换物理Standby为逻辑Standby
执行下列语句,转换物理Standby为逻辑Standby:
SQL>ALTERDATABASERECOVERTOLOGICALSTANDBYDB_NAME;
注意:DB_NAME不是DB_UNIQUE_NAME,不同于物理Standby,逻辑Standby是一个全新的数据库,因此建议你指定一个唯一的与Primary不同的数据库名。另外如果当前准逻辑Standby使用SPFILE启动数据库,那么执行该语句时Oracle会自动修改SPFILE中的相关信息,如果使用PFILE启动数据库,那么在下次执行SHUTDOWN的时候,Oracle会提示你去修改DB_NAME初始化参数的值。
执行该语句前务必确保当前准逻辑Standby已经暂停了REDO应用,另外转换是单向的,即只能由物理Standby向逻辑Standby转换,而不能由逻辑Standby转成物理Standby。这并不仅仅是因为DB_NAME发生了修改,更主要的原因是逻辑Standby仅是数据与Primary一致,其他如存储结构、SCN等,甚至DBID都不相同。
执行转换的过程中,需要应用全部的与LogMiner字典相关的REDO数据。这部分操作完全依赖于Primary数据库DBMS_LOGSTDBY.BUILD的执行,以及传输到Standby数据库端,需要应用的数据量的规模而定。如果Primary数据库执行DBMS_LOGSTDBY.BUILD失败,则转换操作也不会有结果,这时候你恐怕不得不先cancel它,解决Primary数据库的问题之后再尝试执行转换。取消该操作与取消REDO应用一样,当然实际上,也正是取消REDO应用。
4重建逻辑Standby的密钥文件
主要是由于转换操作修改了数据库名,因此密码文件也需要重建,这个操作我们做得比较多,这里就不详述了。
[oracle@localhostdbs]$orapwdfile=/u01/app/oracle/product/10.2.0/db_1/dbs/orapworclpassword=admin
如果已经存在,就不用创建了。缺省情况下,win下口令文件的格式是pwdsid.ora,unix下的格式是orapwSID(大小写敏感)
5调整逻辑Standby初始化参数
之所以要调整初始化参数,一方面是由于此处我们的逻辑Standby是从物理Standby转换来的,某些参数并不适合,甚至可能造成错误,如LOG_ARCHIVE_DEST_n参数的设置。另一方面,由于逻辑Standby默认是以OPENREADWRITE模式打开,有可能存在读写操作,因此会读写本地OnlineRedologs并产生ArchiveLogs,务必需要注意本地的ArchiveLogs路径,不要与接收自Primary数据库的重做日志文件路径冲突。
当然归根结底是因为逻辑Standby是从物理Standby转换而来,因此Standby的初始化参数就需要第二次调整(第一次是创建物理Standby)。
修改初始化参数的方式有多种,既可以通过ALTERSYSTEM命令,也可以先生成PFILE并修改相关参数,然后再根据修改过的PFILE生成SPFILE。
6打开逻辑Standby及应用REDO数据
由于逻辑Standby与Primary数据库事务并不一致,其实质相当于进行了不完全恢复,因此第一次打开时必须指定RESETLOGS子句,如下:
SQL>ALTERDATABASEOPENRESETLOGS;
在逻辑Standby端启动SQL应用,可以通过下列语句进行:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLY;
注意:应用REDO数据时必须是在OPENREADWRITE模式下,这点与物理Standby有明显的区别。
逻辑Standby也可以像物理Standby那样启用实时应用,只需要在启动REDO应用时附加IMMEDIATE子句即可,如:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
如果想停止逻辑Standby数据库的SQL应用,则可通过下列命令进行:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLYIMMEDIATE;
关于LogicalStandby完成创建实例及主备切换,请参考blog:
OracleDataGuardLinux平台LogicalStandby创建实例
http://blog.csdn.net/tianlesoftware/archive/2010/05/06/5564179.aspx
三.管理逻辑Standby的相关视图
1.DBA_LOGSTDBY_EVENTS
可以把该视图看成逻辑Standby操作日志,因此如果发生了错误,可以通过该视图查看近期逻辑Standby都做了些什么。默认情况下,该视图只保留最近100条事件的记录(可以通过相关过程修改保存的记录条数)。
例如:
SQL>SELECTEVENT_TIME,STATUS,EVENTFROMDBA_LOGSTDBY_EVENTS
ORDERBYEVENT_TIMESTAMP;
EVENT_TIMSTATUSEVENT
------------------------------------------------------------------------------
05-MAY-10ORA-16111:logminingandapplysettingup
05-MAY-10ORA-16257:Switchoverinitiatedstopapplysuccess
2.DBA_LOGSTDBY_LOG
该视图用来记录当前的重做日志的应用情况,功能类似于物理Standby中的V$ARCHIVED_LOG。
多数情况下,你只需要关注SEQUENCE#、APPLIED等有限的几个列,即查看日志序号和是否应用,当然该视图还能提供更多信息,如应用的SCN、应用时间等,例如:
SQL>SELECTSEQUENCE#,FIRST_CHANGE#,NEXT_CHANGE#,
TIMESTAMP,APPLIEDFROMDBA_LOGSTDBY_LOG;
SEQUENCE#FIRST_CHANGE#NEXT_CHANGE#TIMESTAMPAPPLIED
----------------------------------------------------
11057216057217105-MAY-10CURRENT
11157217157217505-MAY-10NO
通常情况下,该查询只会返回几条记录,如果说你的数据库操作非常频繁,可能记录数会稍多一些,但如果记录数非常多,那你就需要关注一下,是不是出了什么问题,难道SQL应用没有启动?
3.V$LOGSTDBY_STATS
该视图就是用来显示LogMiner的状态等相关信息,例如:
SQL>SELECT*FROMV$LOGSTDBY_STATS;
NAMEVALUE
-------------------------------------------------------------------------------
numberofpreparers1
numberofappliers5
maximumSGAforLCRcache30
parallelserversinuse9
maximumeventsrecorded100
preservecommitorderTRUE
transactionconsistencyFULL
recordskiperrorsY
recordskipDDLY
recordappliedDDLN
recordunsupportedoperationsN
4.V$LOGSTDBY_PROCESS
该视图显示当前日志应用服务的相关信息。常用于诊断归档日志逻辑应用的性能问题(后面优化部分会涉及),包含的信息也很广,包括:
身份信息:SID、SERIAL#、SPID。
SQL应用进程:COORDINATOR、READER、BUILDER、PREPARER、ANALYZER、或APPLIER。
进程当前的状态:见STATUS_CODE或STATUS列。
该进程当前操作REDO记录最大SCN:HIGH_SCN列。
例如:
SQL>SELECTSID,SERIAL#,SPID,TYPE,STATUS,HIGH_SCNFROMV$LOGSTDBY_PROCESS;
SIDSERIAL#SPIDTYPESTATUS
----------------------------------------------------------------------------
1393036831COORDINATORORA-16116:noworkavailable
1532926833READERORA-16240:Waitingforlogfil
13656835BUILDERORA-16116:noworkavailable
13756837PREPARERORA-16116:noworkavailable
12816841ANALYZERORA-16116:noworkavailable
13216843APPLIERORA-16116:noworkavailable
13326845APPLIERORA-16116:noworkavailable
13016847APPLIERORA-16116:noworkavailable
12916849APPLIERORA-16116:noworkavailable
13116851APPLIERORA-16116:noworkavailable
5.V$LOGSTDBY_PROGRESS
该视图显示LOG应用服务当前进展状况,如当前应用到逻辑Standby的SCN及时间,SQL应用开始应用的SCN及时间,最后接收及应用的SCN和时间等。
例如,查看当前应用的SCN信息:
SQL>SELECTAPPLIED_SCN,LATEST_SCN,MINING_SCN,RESTART_SCNFROMV$LOGSTDBY_PROGRESS;
APPLIED_SCNLATEST_SCNMINING_SCNRESTART_SCN
------------------------------------------
572164572232572166
6.V$LOGSTDBY_STATE
该视图显示SQL应用的大致状态,如Primary数据库的DBID,是否实时应用,当前SQL应用的状态。需要注意的是该视图的STATE列,该列可能有下述的几种状态。应用日志的过程,也是这几种状态相互转换的过程。
1)INITIALIZING初始化状态。
执行ALTERDATABASESTARTLOGICALSTANDBYAPPLY语句,启动SQL应用时,首先就会进入初始化状态,例如:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
SQL>SELECTSESSION_ID,STATEFROMV$LOGSTDBY_STATE;
SESSION_IDSTATE
----------------------------------------
21INITIALIZING
这个状态存在的时间非常短暂,多数情况下只有当ALTERDATABASESTARTLOGICALSTANDBYAPPLY执行时查看V$LOGSTDBY_STATE视图,会看到初始化状态,一旦该命令执行完,状态就被切换为等待字典日志或应用中的状态了。
2)WAITINGFORDICTIONARYLOGS等待数据字典日志。
指第一次初始化时的状态,如刚从物理Standby转换成逻辑Standby,需要首先应用来自Primary端生成的数据字典,在等待Primary数据字典信息时,就会处于这一状态。例如:
SQL>SELECTSESSION_ID,STATEFROMV$LOGSTDBY_STATE;
SESSION_IDSTATE
----------------------------------------
21WAITINGFORDICTIONARYLOGS
这个过程也非常短暂。
3)LOADINGDICTIONARY加载并分析。
当查询V$LOGSTDBY_STATE视图,显示下列状态时,说明处于加载数据字典的状态:
SQL>SELECTSESSION_ID,STATEFROMV$LOGSTDBY_STATE;
SESSION_IDSTATE
----------------------------------------
21LOADINGDICTIONARY
对于比较大型的数据库系统,加载数据字典需要一些时间。此时还可以查询V$lOGMNR_DICTIONARY_LOAD视图获取关于加载的更详细的信息,例如:
SQL>SELECTPERCENT_DONE,COMMANDFROMV$LOGMNR_DICTIONARY_LOAD
WHERESESSION_ID=(SELECTSESSION_IDFROMV$LOGSTDBY_STATE);
APPLYING应用REDO数据。
SQL应用正在处理中,如果要查看当前的处理进度,可以通过V$LOGSTDBY_PROGRESS视图完成。
4)WAITINGONGAP中断等待状态。
SQL应用挖掘并应用了所有可用的REDO数据,正等待新的日志文件,也有可能是由于归档文件有中断造成的。如果查询V$LOGSTDBY_STATE视图时发现处于这一状态,应该同时查询V$ARCHIVE_GAP视图,检查是否有中断的归档。
5)IDLE空闲状态。
处于这一状态也有可能不是好现象,一方面可能是逻辑Standby处理能力优秀,所有活都干完了;也可能是Primary数据库发送日志或逻辑Standby日志出现了问题,导致SQL应用无活可干,因此处于空闲状态。
如果你发现你的逻辑Standby数据库长期处于这一状态,建议查询DBA_LOGSTDBY_LOG视图,确认Primary端产生的日志文件能被逻辑Standby数据库正常接收。
6)SQLAPPLYNOTON。
如果你查询V$LOGSTDBY_STATE视图时发现提示这一状态,说明逻辑Standby数据库根本没启动SQL应用。
四.逻辑Standby数据库的自定义配置
4.1取消自动删除归档文件
逻辑Standby应用完归档后会自动删除该归档文件,这一极具体贴意味的特性,是由逻辑Standby中的一项参数控制的,如果希望禁用自动删除的功能,可以执行下列语句:
SQL>EXECDBMS_LOGSTDBY.APPLY_SET('LOG_AUTO_DELETE','FALSE');
PL/SQLproceduresuccessfullycompleted.
在某些情况下确实需要禁用归档文件的自动删除功能,如逻辑Standby需要执行FlashbackDatabase操作,如果你想恢复到之前的某个时间点,然后再接着应用,就必须要有该时间点后对应的归档,假如LOG_AUTO_DELETE为TRUE的话,应用过的归档已经被删除,想回都回不去。
提示:如何知道当前逻辑Standby的参数设置呢?Oracle专门提供了一个数据字典DBA_LOGSTDBY_PARAMETERS,用于查询逻辑Standby当前的参数,例如:
SQL>SELECT*FROMDBA_LOGSTDBY_PARAMETERS;
NAMEVALUE
-------------------------------------------------------------------------------
FIRST_SCN580428
PREP_DICT_RECEIVED
PRIMARY3409053734
LMNR_SID1
GUARD_STANDBYREADY
LOG_AUTO_DELETEFALSE
APPLY_SCN581410
需要注意的是,如果禁止了Standby归档文件的自动删除功能,一定要有相应的其他解决方案,不能说取消了自动删除功能,之后逻辑Standby数据库接收到的Standby归档文件就不再管它,这肯定会产生问题,最起码要考虑到逻辑Standby数据库的存储空间是有限的。
逻辑Standby数据库接收到的归档文件并不会显示在V$ARCHIVED_LOG视图中,因此以为通过RMAN中的配置自动删除这些文件的希望也是会落空的。对于这类文件的删除,正确的删除方法通常会按照如下步骤操作:
首先执行DBMS_LOGSTDBY.PURGE_SESSION,该过程会检查当前所有接收到的归档日志文件,对于那些已经应用过,不再需要的文件进行标记,例如:
SQL>EXECUTEDBMS_LOGSTDBY.PURGE_SESSION;
PL/SQLproceduresuccessfullycompleted.
然后,查询数据字典DBA_LOGMNR_PURGED_LOG,所有被DBMS_LOGSTDBY.PURGE_SESSION标记不再需要的日志都会记录在这里,例如:
SQL>SELECT*FROMDBA_LOGMNR_PURGED_LOG;
FILE_NAME
-------------------------------------------------
/U01/STD/ARC00109_0680477835.001
该字典只有一列,即归档文件的实际路径。最后根据显示的路径找到这些文件,然后在操作系统中删除即可。
4.2启动实时应用
在默认情况下,逻辑Standby会等待单个归档文件全部接收之后再启动REDO应用,如果Standby数据库配置了StandbyRedologs,就可以打开实时应用(Real-TimeApply),这样逻辑Standby端就不再需要等待接收完归档文件,只要有REDO数据写入本地的StandbyRedologs,即可通过相应的进程实时写向逻辑Standby数据库。
启动逻辑Standby数据库的实时应用非常简单,只需要在逻辑Standby启动SQL应用时加上IMMEDIATE子句即可,例如:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
4.3定义DBA_LOGSTDBY_EVENTS记录的事件
要查看逻辑Standby执行REDO应用时的操作信息,一般有两种方式:
一种是查看Oracle数据库的警告日志文件Alert(当然该文件不仅仅包括REDO应用的信息),
另一种是直接查询数据字典DBA_LOGSTDBY_EVENTS。
如果只是想查看日志应用信息的话,数据字典DBA_LOGSTDBY_EVENTS实用性更高,毕竟术业有专攻嘛。不过默认情况下该字典中只保留最近的100条消息(可以通过V$LOGSTDBY_STATS视图查看保留的记录数),这个数量过于偏小,如果要修改该字典中记录的事件数量,也是通过DBMS_LOGSTDBY.APPLY_SET过程完成。例如,设置该字典保留最近999条事件,执行语句如下:
JSSLDG>EXECDBMS_LOGSTDBY.APPLY_SET('MAX_EVENTS_RECORDED','999');
PL/SQLproceduresuccessfullycompleted.
注意:执行DBMS_LOGSTDBY.APPLY_SET过程时,REDO应用必须处于停止状态。
SQL>alterdatabasestoplogicalstandbyapply;
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
另外,还可以通过DBMS_LOGSTDBY.APPLY_SET过程设置是否记录DDL应用的事件,例如:
SQL>EXECDBMS_LOGSTDBY.APPLY_SET('RECORD_APPLIED_DDL','TRUE');
PL/SQLproceduresuccessfullycompleted.
注:该过程同样要停REDO.
然后启动REDO应用,查看当前的最大保存记录数及是否记录DDL应用的事件:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
SQL>select*fromv$logstdby_statswherenamein('maximumeventsrecorded','recordappliedDDL');
NAMEVALUE
-------------------------------------------------------------------------------
maximumeventsrecorded999
recordappliedDDLN
五.修改逻辑Standby端数据
相对物理Standby,逻辑Standby的管理要复杂一点点。这个就是管理一个半数据库和管理两个数据库的差异(假设DataGuard环境为一主一备的情况下),毕竟逻辑Standby只是逻辑上,仿佛与Primary数据库一致,其实它是一个独立运行的,甚至可能与Primary数据库完全不同的数据库系统,对于这种配置环境,管理上多花点工夫想想也是应该的。
5.1指定对象跳过应用
在默认情况下,接收自Primary的REDO数据中,所有能够被逻辑Standby数据库支持的操作都会在逻辑Standby端执行。如果你希望跳过对某些对象的某些操作的话,DBMS_LOGSTDBY.SKIP就能派上用场了。
先来看看DBMS_LOGSTDBY.SKIP的语法:
DBMS_LOGSTDBY.SKIP(
stmtINVARCHAR2,
schema_nameINVARCHAR2DEFAULTNULL,
object_nameINVARCHAR2DEFAULTNULL,
proc_nameINVARCHAR2DEFAULTNULL,
use_likeINBOOLEANDEFAULTTRUE,
escINCHAR1DEFAULTNULL);
除stmt外,其他都是可选参数,并且看字面意义就能明白其所指。例如,你想跳过SCOTT用户下对dept表的DML操作,可以通过执行下列语句实现(执行该过程前需要先停止REDO应用):
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
SQL>EXECDBMS_LOGSTDBY.SKIP('DML','SCOTT','DEPT');
PL/SQLproceduresuccessfullycompleted.
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
5.2恢复对象同步
如果逻辑Standby中的某些表取消了与Primary的同步维护,现在希望再恢复同步,没问题,DBMS_LOGSTDBY家大业大,它还有个叫UNSKIP的门生专干这个。
我们来看一下DBMS_LOGSTDBY.UNSKIP的语法:
DBMS_LOGSTDBY.UNSKIP(
stmtINVARCHAR2,
schema_nameINVARCHAR2,
object_nameINVARCHAR2);
三项均为必选参数,各参数的定义与SKIP过程相同。
下面演示恢复tmp1表的同步。
首先查看当前逻辑Standby都有哪些对象处于不同步状态,可以通过DBA_LOGSTDBY_SKIP视图查看,例如:
SQL>select*fromdba_logstdby_skip;
ERRORSTATEMENT_OPTOWNERNAMEUEPROC
--------------------------------------------------------------
NDMLSCOTTDEPTY
NINTERNALSCHEMASYSTEM%Y
NINTERNALSCHEMASYS%Y
NINTERNALSCHEMAOLAPSYS%Y
NINTERNALSCHEMASI_INFORMT%Y
NINTERNALSCHEMAMGMT_VIEW%Y
NINTERNALSCHEMAORDPLUGINS%Y
NINTERNALSCHEMAXDB%Y
NINTERNALSCHEMASYSMAN%Y
NINTERNALSCHEMAWMSYS%Y
NINTERNALSCHEMADBSNMP%Y
注意在执行DBMS_LOGSTDBY.UNSKIP过程前,要停止当前的SQL应用状态:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
执行DBMS_LOGSTDBY.UNSKIP过程,恢复前面停止的scott.tmp1表的应用:
SQL>executedbms_logstdby.unskip('DML','SCOTT','dept');
PL/SQLproceduresuccessfullycompleted.
5.3添加或重建对象
指定对象跳过应用虽然被取消,但是有可能在此期间由于Primary数据库做过数据修改,两端此时已经不同步,如果Standby端继续应用极有可能导致应用错误的数据。
对于这类情况,Oracle也早有预见,DBMS_LOGSTDBY包中还有一个过程叫INSTANTIATE_TABLE,专门用来同步一下跳过的对象,以保持与Primary数据库的一致。
DBMS_LOGSTDBY.INSTANTIATE_TABLE的调用语法如下:
DBMS_LOGSTDBY.INSTANTIATE_TABLE(
schema_nameINVARCHAR2,
table_nameINVARCHAR2,
dblinkINVARCHAR2);
除了SCHEMA名称和表名称外,还需要提供一个数据库链,因此这里我们首先在逻辑Standby端创建一个连接Primary数据库的数据库链:
SQL>CREATEDATABASELINKPRE_TBL_DATACONNECTTOSYSTEMIDENTIFIEDBYADMIN
USING'ORCL_PD';
Databaselinkcreated.
执行使用DBMS_LOGSTDBY.INSTANTIATE_TABLE过程,重新同步SCOTT.TMP1表(注意执行该过程前别忘了暂停当前的SQL应用):
SQL>EXECDBMS_LOGSTDBY.INSTANTIATE_TABLE('SCOTT','DEPT','PRE_TBL_DATA');
PL/SQLproceduresuccessfullycompleted.
SQL>SELECT*FROMSCOTT.DEPT;
对象已被重建,然后重新启动SQL应用即可:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
5.4逻辑Standby端修改数据
逻辑Standby的一个极具实用价值的特性就是可以边查询边应用,因此将其作为报表服务器专供查询是个很不错的想法,而且逻辑Standby相对于物理Standby而言更具灵活性,如我们可以在逻辑Standby上,对一些表创建Primary数据库并不方便创建的索引、约束,甚至可以做DML/DDL操作(当然,需要注意不要破坏了与Primary数据库之间同步的逻辑关系)。
不过由于此时DataGuard仍然控制着对逻辑Standby数据库中表的读写操作,因此,如果你想对逻辑Standby中的数据做些什么的话,ALTERSESSIONDISABLE|ENABLEGUARD语句就必须牢记在心了,它拥有像"芝麻开门"一样神奇的能力。下面我们就来感受一下吧。
在逻辑Standby端启动SQL应用的情况下,执行DDL操作:
SQL>GRANTDBATOSCOTT;
Grantsucceeded.
SQL>CONNSCOTT/TIGER;
Connected.
SQL>CREATETABLEDAVEASSELECT*FROMUSER_OBJECTS;
CREATETABLEDAVEASSELECT*FROMUSER_OBJECTS
*
ERRORatline1:
ORA-01031:insufficientprivileges
出错了,提示权限不足,实际上SCOTT被授予了DBA角色,肯定拥有CREATETABLE权限的,因此此处与用户的权限无关,而是有其他因素制约了SCOTT无法进行修改。
下面禁用DataGuard保护之后,再次尝试操作数据:
SQL>ALTERSESSIONDISABLEGUARD;
Sessionaltered.
SQL>CREATETABLEDAVEASSELECT*FROMUSER_OBJECTS;
Tablecreated.
这下可以了,这就是DataGuard的作用。
注意:数据修改完之后,别忘了再次启用DataGuard,以避免不经意的误操作对逻辑Standby的配置造成影响(你说不手动启用DataGuard保护,直接退出行不行,当然也可以,ALTERSESSION所做修改仅对当前会话有效,退出重新登录,原会话设置自然就失效了)。
SQL>ALTERSESSIONENABLEGUARD;
Sessionaltered.
按照Oracle的建议,还是尽可能不要在逻辑Standby端执行DML之类操作,以免破解其与Primary之间同步的逻辑关系,
也可以通过下列语句查看当前数据库是否处于DataGuard保护状态:
SQL>SELECTGUARD_STATUSFROMV$DATABASE;
GUARD_S
-------
ALL
该参数对应三个值:
ALL:表示对数据库中所有对象启动修改保护,除SYS用户外,其他用户均不能直接修改数据。
STANDBY:表示对处于逻辑Standby维护关系的对象启动修改保护,除SYS用户外,其他用户均不能直接修改数据。
NONE:不启动数据保护。
如果要永久设置数据库的DataGuard保护模式,则是通过ALTERDATABASE命令来完成,可指定的值也正是上述的三种,例如:
SQL>ALTERDATABASEGUARDSTANDBY;
Databasealtered.
执行完上述语句后,DataGuard仅对处于逻辑Standby维护关系的对象进行防止修改操作的保护。
考虑到逻辑Standby中也有可能对数据进行修改(正如上例演示),因此这里引申谈一谈在逻辑Standby数据库中,约束和触发器的执行模式。默认情况下,约束和触发器都能在逻辑Standby端正常运行。约束和触发器在逻辑Standby端的执行可以分成两种情况:
对于SQL应用维护的约束和触发器,由于在Primary数据库已经检查过约束,因此Standby端不需要再次检查;触发器的情况也是这样,Primary端操作时结果已经被记录,因此逻辑Standby端将直接被应用,而不会二次触发。
对于没有SQL应用维护的约束和触发器,其执行情况与普通的Oracle数据库环境相同。
5.5重定义REDO应用执行的操作
对于逻辑Standby数据库,你甚至可以通过编写自定义的PROCEDURE,来重新定义SQL应用时执行的操作。
如逻辑Standby数据库的文件路径与Primary数据库路径不同,如果是物理Standby,可以通过*_FILE_NAME_CONVERT之类的参数处理,在逻辑Standby环境中这几个参数无效,应该如何处理呢?答案就是通过编写自定义的过程,修改SQL应用时执行的操作。
下面通过示例,演示通过编写自定义的PROCEDURE,修改创建表空间时逻辑Standby端数据文件的路径。
首先当然是创建一个过程,建议创建在SYS下,因为在这个用户下的操作肯定不会有同步的问题,如下所示:
SQL>CREATEORREPLACEPROCEDURESYS.HANDLE_TBS_DDL(
2OLD_STMTINVARCHAR2,
3STMT_TYPINVARCHAR2,
4SCHEMAINVARCHAR2,
5NAMEINVARCHAR2,
6XIDUSNINNUMBER,
7XIDSLTINNUMBER,
8XIDSQNINNUMBER,
9ACTIONOUTNUMBER,
10NEW_STMTOUTVARCHAR2
11)AS
12BEGIN
13
14NEW_STMT:=REPLACE(OLD_STMT,'/u01/oradata/orcl_pd/','/u01/oradata/orcl_st');
15ACTION:=DBMS_LOGSTDBY.SKIP_ACTION_REPLACE;
16
17EXCEPTION
18WHENOTHERSTHEN
19ACTION:=DBMS_LOGSTDBY.SKIP_ACTION_ERROR;
20NEW_STMT:=NULL;
21ENDHANDLE_TBS_DDL;
22/
Procedurecreated.
逻辑非常简单,基本上就是一个REPLACE,不过PROCEDURE中声明的变量看起来很多,这个是固定格式,不建议修改。
停止逻辑Standby的SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
如果不停,PROCEDURE不能生效。
执行DBMS_LOGSTDBY.SKIP过程,将编写的过程注册到表空间处理的SQL应用中:
SQL>EXECDBMS_LOGSTDBY.SKIP(stmt=>'TABLESPACE',proc_name=>'sys.handle_tbs_ddl');
PL/SQLproceduresuccessfullycompleted.
这里也要借助DBMS_LOGSTDBY.SKIP过程实现。该过程功能非常强大,而且操作非常灵活。
重启SQL应用:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
测试一下,在Primary端创建一个新的表空间:
SQL>CREATETABLESPACEBOOKSDATAFILE'/u01/oradata/orcl_pd/books01.dbf'SIZE20m;
Tablespacecreated.
SQL>SELECTFILE_NAMEFROMDBA_DATA_FILESWHERETABLESPACE_NAME='BOOKS';
FILE_NAME
-----------------------------------------------------------------------------
/u01/oradata/orcl_pd/books01.dbf
转向逻辑Standby数据库查看:
SQL>SELECTFILE_NAMEFROMDBA_DATA_FILESWHERETABLESPACE_NAME='BOOKS';
FILE_NAME
----------------------------------------------------------------------------
/u01/oradata/orcl_st/books01.dbf
表空间成功创建,并且数据文件路径也被转换为我们指定的路径。
此时如果你查看Alert日志文件,会发现其中记录下了类似这样的信息:
LOGSTDBYstmt:createtablespacebooksdatafile'/u01/oradata/orcl_pd/books01.dbf'size20m
LOGSTDBYstatus:ORA-16110:逻辑备用应用DDL的用户过程处理
LOGSTDBYid:XID0x0001.009.000000d1,hSCN0x0000.0012ec41,
lSCN0x0000.0012ec41,Thread1,RBA0x007f.0000079a.80,
txnCscn0x0000.0012ec43,PID5816,ORACLE.EXE(P004)
LOGSTDBYstmt:createtablespacebooksdatafile'/u01/oradata/orcl_st/books01.dbf'size20m
LOGSTDBYstatus:ORA-16202:跳过过程已请求替换语句
LOGSTDBYid:XID0x0001.009.000000d1,hSCN0x0000.0012ec41,
lSCN0x0000.0012ec41,Thread1,RBA0x007f.0000079a.80,
txnCscn0x0000.0012ec43,PID5816,ORACLE.EXE(P004)
createtablespacebooksdatafile'/u01/oradata/orcl_st/books01.dbf'size20m
Completed:createtablespacebooksdatafile'/u01/oradata/orcl_st/books01.dbf'size20m
LOGSTDBYstmt:createtablespacebooksdatafile'/u01/oradata/orcl_st/books01.dbf'size20m
LOGSTDBYstatus:ORA-16204:成功应用了DDL
六.优化逻辑Standby数据同步性能
6.1调整APPLIER进程数
APPLIER进程就是执行应用操作的进程。在默认情况下逻辑Standby会启动5个APPLIER进程,如果日志应用任务繁重(或者说Primary数据库修改量较大),则适当多启动几个APPLIER进程有助于提高应用的效率。
先查看当前空闲的APPLIER进程数:
SQL>SELECTCOUNT(*)ASIDLE_APPLIERFROMV$LOGSTDBY_PROCESSWHERETYPE='APPLIER'andstatus_code=16166;
IDLE_APPLIER
------------
0
返回结果为0,难道都在忙?这个真不一定,空闲的APPLIER进程数为0不一定代表应用非常繁忙,也有可能是因为当前没什么需要应用的日志,甚至都没启动应用进程。
说明:status_code=16166表示进程是空闲状态,因为stats_code=16166对应的状态说明列STATS为ORA-16116:noworkavailable。
检查事务的应用情况:
SQL>SELECTNAME,VALUEFROMV$LOGSTDBY_STATSWHERENAMELIKE'transactions%';
NAMEVALUE
--------------------------------
trans358
trans358
如果ready-applied的值比APPLIER进程数的两倍还要大,则说明DBA有必要考虑增加APPLIER进程的数目了,反之如果applied与ready的值差不多大,或者其差比APPLIER进程数还小,则说明APPLIER进程数偏多,DBA有必要考虑适当减小进程的数目。
如果确认当前APPLIER进程都非常繁忙,要增加APPLIER进程,可按如下步骤操作:
1)停止逻辑Standby端的SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
2)执行下列语句,调整APPLIER进程数为10:
SQL>EXECUTEDBMS_LOGSTDBY.APPLY_SET('APPLY_SERVERS',10);
PL/SQLproceduresuccessfullycompleted.
3)重新启动SQL应用:
JSSLDG>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
4)查出的就是当前运行的APPLIER进程数:
SQL>SELECTCOUNT(0)FROMV$LOGSTDBY_PROCESSWHERETYPE='APPLIER';
COUNT(0)
----------
10
也可以通过V$LOGSTDBY_STATS视图查询,例如:
SQL>SELECT*FROMV$LOGSTDBY_STATSWHERENAME='numberofappliers';
NAMEVALUE
---------------------------------------------------------------------
numbe10
6.2调整PREPARER进程数
PREPAPER进程将接收到的REDO数据中的块修改转换成LCRs(LogicalChangeRecords)。一般需要调整PREPAPER进程数的机会不多,通常只有一种情况:APPLIER进程有空闲,TransactionsReady还很多,但没有空闲的PREPAPER进程,这时候DBA可能就需要增加一些PREPAPER进程。
先检查空闲PREPAPER进程数量:
SQL>SELECTCOUNT(*)ASIDLE_PREPARERFROMV$LOGSTDBY_PROCESS
WHERETYPE='PREPARER'andstatus_code=16166;
IDLE_PREPARER
-------------
0
说明:如果显示为0,别怕,也有可能是因为当前没什么新的REDO数据需要处理。
如果确实需要调整PREPAPER进程数量,可以按照下列步骤进行。
首先停止SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
调整PREPAPER进程数量为4(默认只有1个PREPAPER进程):
SQL>EXECUTEDBMS_LOGSTDBY.APPLY_SET('PREPARE_SERVERS',4);
PL/SQLproceduresuccessfullycompleted.
重新启动SQL应用即可:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
查看当前启动的PREPAPER进程数,查询V$LOGSTDBY_STATS视图,例如:
SQL>SELECT*FROMV$LOGSTDBY_STATSWHERENAME='numberofpreparers';
NAMEVALUE
---------------------------------------------------------------------
numbe4
6.3调整LCR使用的内存
LCR中保存的是转换后的块修改的记录,这部分数据保存在SGA中.
查询当前LCR可用的最大内存:
SQL>SELECT*FROMV$LOGSTDBY_STATSWHERENAME='maximumSGAforLCRcache';
NAMEVALUE
--------------------------------------------------------
maximumSGAforLCRcache30
显示的参数值默认单位为M,当前结果显示LCR内存区可用空间为30M。
要增加LCR可用的内存,可按照下列步骤操作。
1)首先还是需要停止SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
Databasealtered.
2)调整内存大小为100M:
SQL>EXECDBMS_LOGSTDBY.APPLY_SET('MAX_SGA',100);
PL/SQLproceduresuccessfullycompleted.
3)最后重启SQL应用即可
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
Databasealtered.
6.4调整事务应用方式
在默认情况下逻辑Standby端事务应用顺序与Primary数据库提交顺序相同。如果DBA希望逻辑Standby端事务应用不按照Primary数据库顺序执行的话,可以按照下列步骤操作:
1)停止SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
2)允许事务不按照Primary的提交顺序应用:
SQL>EXECUTEDBMS_LOGSTDBY.APPLY_SET('PRESERVE_COMMIT_ORDER','FALSE');
3)重新启动SQL应用:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
恢复逻辑Standby按照事务提交顺序应用的话,可按照下列步骤操作:
1)先停止SQL应用:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
2)重置参数PRESERVE_COMMIT_ORDER的初始值:
SQL>EXECUTEDBMS_LOGSTDBY.APPLY_UNSET('PRESERVE_COMMIT_ORDER');
3)重新启动SQL应用:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
七.应用REDO数据到Standby数据库
1.物理Standby应用REDO数据
物理Standby启动REDO应用,数据库要处于MOUNT状态或是OPENREADONLY状态,启动REDO应用的命令相信大家已经非常熟悉了。
前台应用:
SQL>ALTERDATABASERECOVERMANAGEDSTANDBYDATABASE;
语句执行完成后,不会将控制权返回到命令行窗口,除非你手动中止应用。在这种情况下如果还需要对数据库进行操作,只能新开一个命令行连接,在Oracle8i刚推出Standby特性时(那时不叫DataGuard),只提供了这种方式。
后台应用:
SQL>ALTERDATABASERECOVERMANAGEDSTANDBYDATABASEDISCONNECT;
这是现在比较通用的方式,语句执行完后,控制权自动返回到当前的命令行模式,REDO应用以后台进程运行。
启动实时应用,附加USINGCURRENTLOGFILE子句即可:
SQL>ALTERDATABASERECOVERMANAGEDSTANDBYDATABASEUSINGCURRENTLOGFILE;
如果要停止REDO应用,执行下列语句即可:
SQL>ALTERDATABASERECOVERMANAGEDSTANDBYDATABASECANCEL;
2.逻辑Standby应用REDO数据
SQL应用的原理是将接收到的REDO数据转换成SQL语句在逻辑Standby数据库端执行,因此逻辑Standby需要启动至OPEN状态。
(1)启动SQL应用。逻辑Standby数据库启动SQL应用没有前、后台运行之说,语句执行完之后,控制权就会自动返回当前命令行窗口。要启动SQL应用,直接执行下列语句即可:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLY;
如果要启动实时应用,附加IMMEDIATE子句即可,例如:
SQL>ALTERDATABASESTARTLOGICALSTANDBYAPPLYIMMEDIATE;
(2)停止SQL应用,如:
SQL>ALTERDATABASESTOPLOGICALSTANDBYAPPLY;
由于是执行SQL语句的方式应用REDO数据,因此上述语句的执行需要等待当前执行的SQL触发的事务结束,才能真正停止REDO应用的状态。
如果不考虑事务执行情况,马上停止REDO应用,可以通过下列的语句来完成:
SQL>ALTERDATABASEABORTLOGICALSTANDBYAPPLY;
注:整理自李丙洋《涂抹Oracle》