JSSLDG2> select event_time,status,event from dba_logstdby_events;
EVENT_TIME STATUS EVENT
------------------- ----------------------------------------- ----------------------------------------
2008-03-06 08:58:11 ORA-16112: 日志挖掘和应用正在停止
2008-03-06 09:02:00 ORA-16111: 日志挖掘和应用正在启动
2008-03-06 09:52:53 ORA-16128: 已成功完成用户启动的停止应用操作
2008-03-12 15:52:53 ORA-16111: 日志挖掘和应用正在启动
2008-03-12 16:09:17 ORA-16226: 由于不支持而跳过DDL ALTER DATABASEOPEN
2008-03-05 17:21:46 ORA-16111: 日志挖掘和应用正在启动
..............................
JSSLDG2> select sequence#,first_change#,next_change#,timestamp,applied from dba_logstdby_log;
SEQUENCE# FIRST_CHANGE# NEXT_CHANGE# TIMESTAMP APPLIED
---------- ------------- ------------ ------------------- --------
869 1319212 1319811 2008-03-12 16:09:15 CURRENT
从名字就大致猜的出来,该视图显示的是状态信息,没错,你猜对了,该视图就是用来显示LogMiner的统计信息及状态。
JSSLDG2> select *from v$logstdby_stats;
NAME VALUE
---------------------------------------- ---------------
number of preparers 1
number of appliers 5
maximum SGA for LCR cache 30
parallel servers in use 9
maximum events recorded 100
preserve commit order TRUE
transaction consistency FULL
record skip errors Y
record skip DDL Y
record applied DDL N
.........................
※ SQL 应用进程:COORDINATOR, READER, BUILDER, PREPARER, ANALYZER, 或APPLIER
※ 进程当前的状态:见status_code 或status 列
※ 该进程当前操作redo 记录最大SCN:high_scn 列
JSSLDG2> select sid,serial#,spid,type,status,high_scn from v$logstdby_process;
SID SERIAL# SPID TYPE STATUS HIGH_SCN
-------- ------- -------- --------------- ----------------------------------------------- ----------
145 1 508 COORDINATOR ORA-16116: 无可用工作 1319811
146 2 2464 READER ORA-16240: 正在等待日志文件(线程号1,序列号870) 1319811
143 1 1512 BUILDER ORA-16116: 无可用工作 1319742
142 1 4000 PREPARER ORA-16116: 无可用工作 1319741
139 1 2980 ANALYZER ORA-16116: 无可用工作 1319707
135 1 1648 APPLIER ORA-16116: 无可用工作 1319430
138 1 2332 APPLIER ORA-16116: 无可用工作 1319439
132 1 2200 APPLIER ORA-16116: 无可用工作 1319443
134 1 4020 APPLIER ORA-16116: 无可用工作
...........................................
该视图显示log 应用服务当前进展状况,比如当前应用到逻辑standby 的scn 及时间,sql 应用开始应用的scn 及时间,最后接收及应用的scn 和时间等等。
JSSLDG2> select * from v$Logstdby_progress;
APPLIED_SCN APPLIED_TIME RESTART_SCN RESTART_TIME LATEST_SCNLATEST_TIME MINING_SCN MINING_TIME
----------- ------------------- ----------- ------------------- ---------- ------------------- ---------- -------------------
1319810 2008-03-12 16:06:51 1319662 2008-03-12 16:03:22 1319810 2008-03-12 16:45:331319811 2008-03-12 16:06:51
该视图就最简单了,就是显示sql 应用的大致状态,比如primary 库的dbid 啦,是否启动了实时应用啦,当前sql 应用的状态啦之类。
※ INITIALIZING: LogMiner session 已创建并初始化
※ LOADING DICTIONARY: SQL 应用调用LogMiner 字典
※ WAITING ON GAP: SQL 应用正等待日志文件,可能有中断
※ APPLYING: SQL 应用正在工作
※ WAITING FOR DICTIONARY LOGS: SQL 应用等待LogMiner 字典信息
※ IDLE: SQL 应用工作非常出色,已经干的没什么可干了:)
JSSLDG2> select * from v$Logstdby_state;
PRIMARY_DBID SESSION_ID REALTIME_APPLY STATE
------------ ---------- -------------------- ----------------------
3408827880 42 Y APPLYING
1、接收到的归档文件
前章曾经提到,逻辑standby 应用完归档后会自动删除该归档文件,该特性你如果觉着不爽,没关系,执行下面这个过程,屏蔽掉它:
JSSLDG2> EXECUTE DBMS_LOGSTDBY.APPLY_SET('LOG_AUTO_DELETE', FALSE);
实时写向standby,这样就可以尽可能保持standby 与primary 的同步。
JSSLDG2> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
JSSLDG2> select *from v$logstdby_stats where name='maximum events recorded';
NAME VALUE
-------------------------------------------- ---------------
maximum events recorded 100
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> execute dbms_logstdby.apply_set('max_events_recorded','999');
PL/SQL 过程已成功完成。
JSSLDG2> alter database start logical standby apply immediate;
数据库已更改。
JSSLDG2> select *from v$logstdby_stats where name='maximum events recorded';
NAME VALUE
-------------------------------------------- ---------------
maximum events recorded 999
JSSLDG2> execute dbms_logstdby.apply_set('RECORD_APPLIED_DDL','TRUE');
默认情况下,接收自primary 的redo 数据中,所有能够被standby 支持的操作都会在逻辑standby 端执行,如果你希望跳过对某些对象的某些操作的话,DBMS_LOGSTDBY.SKIP 就能被派上用场了。
DBMS_LOGSTDBY.SKIP (
stmt IN VARCHAR2,
schema_name IN VARCHAR2 DEFAULT NULL,
object_name IN VARCHAR2 DEFAULT NULL,
proc_name IN VARCHAR2 DEFAULT NULL,
use_like IN BOOLEAN DEFAULT TRUE,
esc IN CHAR1 DEFAULT NULL);
STMT关键字 | 包含的操作 |
NON_SCHEMA_DDL | 不属于模式对象的所有其它ddl操作 |
提示:使用该关键字时,SCHEMA_NAME和OBJECT_NAME两参数也必须指定。 | |
SCHEMA_DDL | 创建修改删除模式对象的所有ddl操作(例如: tables, indexes, and columns) |
提示:使用该关键字时,SCHEMA_NAME和OBJECT_NAME两参数也必须指定。 | |
DML | Includes DML statements on a table (for example: INSERT, UPDATE, and DELETE) |
CLUSTER | AUDIT CLUSTER |
CREATE CLUSTER | |
DROP CLUSTER | |
TRUNCATE CLUSTER | |
CONTEXT | CREATE CONTEXT |
DROP CONTEXT | |
DATABASE LINK | CREATE DATABASE LINK |
CREATE PUBLIC DATABASE LINK | |
DROP DATABASE LINK | |
DROP PUBLIC DATABASE LINK | |
DIMENSION | ALTER DIMENSION |
CREATE DIMENSION | |
DROP DIMENSION | |
DIRECTORY | CREATE DIRECTORY |
DROP DIRECTORY | |
INDEX | ALTER INDEX |
CREATE INDEX | |
DROP INDEX | |
PROCEDURE | ALTER FUNCTION |
ALTER PACKAGE | |
ALTER PACKAGE BODY | |
ALTER PROCEDURE | |
CREATE FUNCTION | |
CREATE LIBRARY | |
CREATE PACKAGE | |
CREATE PACKAGE BODY | |
CREATE PROCEDURE | |
DROP FUNCTION | |
DROP LIBRARY | |
DROP PACKAGE | |
DROP PACKAGE BODY | |
DROP PROCEDURE | |
PROFILE | ALTER PROFILE |
CREATE PROFILE | |
DROP PROFILE | |
ROLE | ALTER ROLE |
CREATE ROLE | |
DROP ROLE | |
SET ROLE | |
ROLLBACK STATEMENT | ALTER ROLLBACK SEGMENT |
CREATE ROLLBACK SEGMENT | |
DROP ROLLBACK SEGMENT | |
SEQUENCE | ALTER SEQUENCE |
CREATE SEQUENCE | |
DROP SEQUENCE | |
SYNONYM | CREATE PUBLIC SYNONYM |
CREATE SYNONYM | |
DROP PUBLIC SYNONYM | |
DROP SYNONYM | |
TABLE | ALTER TABLE |
CREATE TABLE | |
DROP TABLE | |
TABLESPACE | CREATE TABLESPACE |
DROP TABLESPACE | |
TRUNCATE TABLESPACE | |
TRIGGER | ALTER TRIGGER |
CREATE TRIGGER | |
DISABLE ALL TRIGGERS | |
DISABLE TRIGGER | |
DROP TRIGGER | |
ENABLE ALL TRIGGERS | |
ENABLE TRIGGER | |
TYPE | ALTER TYPE |
ALTER TYPE BODY | |
CREATE TYPE | |
CREATE TYPE BODY | |
DROP TYPE | |
DROP TYPE BODY | |
USER | ALTER USER |
CREATE USER | |
DROP USER | |
VIEW | CREATE VIEW |
DROP VIEW |
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> executedbms_logstdby.skip('DML','JSS','TMP1');
PL/SQL 过程已成功完成。
JSSLDG2> alter database start logical standby apply;
数据库已更改。
提示:DBMS_LOGSTDBY.SKIP 的功能非常强大,限于篇幅,这里仅举示例,而且由于其操作非常灵活,此篇俺也不可能就其用法做个一一列举,因此,更丰富的操作方式就留待看官们下头自行发现去吧:)
三、修改逻辑standby端数据
我们前面提到,逻辑standby 一个极具实用价值的特性即是可以边查询边应用,因此将其做为报表服务器专供查询是个很不错的想法,而且逻辑standby 相对于物理standby 而言更具灵活性,比如我们可以在逻辑standby上,对一些表创建primary 库上并不方便创建的索引,约束,甚至可以做dml,ddl 操作(当然,需要注意不要破坏了与primary 之间同步的逻辑关系)。不过由于此时dg 仍然控制着对逻辑standby 表的读写操作,因此,如果你想对逻辑standby 中的数据做些什么的话,alter session database disable|enable guard 语句就必须牢记在心了,它拥有像“芝麻开门”一样神奇的能力,不信?下面我们就来感受一下吧。
JSSLDG2> create table tmp55 as select * From b;
create table tmp55 as select * From b
*
第1 行出现错误:
ORA-01031: 权限不足
JSSLDG2> alter session disable guard;
会话已更改。
JSSLDG2> create table tmp55 as select * From b;
表已创建。
只有关闭了guard 保护之后,才能操作数据,然后别忘了再启用guard,以避免不经意的操作对逻辑standby 的配置造成影响。
JSSLDG2> alter session enable guard;
会话已更改。
如果说,某些表或者数据不需要dataguard 保护(比如一些在逻辑standby 端生成的统计表),这个时候就需要DBMS_LOGSTDBY.SKIP,前头已经介绍过了dbms_logstdby.skip 的基本用法,下面我们来具体演示一下!
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> executexecute dbms_logstdby.skip('SCHEMA_DDL','JSS','TMP%'); --跳过对象的ddl 操作
PL/SQL 过程已成功完成。
JSSLDG2> executedbms_logstdby.skip('DML','JSS','TMP%'); --跳过对象的dml 操作
PL/SQL 过程已成功完成。
JSSLDG2> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
数据库已更改。
JSSLDG2> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
JSSLDG2> select max(id) from jss.b;
Max(id)
----------
9
JSSLDG2> select sequence#,applied from dba_logstdby_log;
SEQUENCE# APPLIED
---------- --------
872 YES
JSSWEB> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
JSSWEB> insert into jss.tmp1 values ('i');
已创建1 行。
JSSWEB> insert into jss.b values (10);
已创建1 行。
JSSWEB> commit;
提交完成。
JSSWEB> alter system switch logfile;
系统已更改。
JSSWEB> select max(sequence#) from v$archived_log;
MAX(SEQUENCE#)
--------------
873
JSSLDG2> select sequence#,applied from dba_logstdby_log;
SEQUENCE# APPLIED
---------- --------
873 YES
JSSLDG2> select max(id) from b;
Max(id)
----------
10
JSSLDG2> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
如果说某些表某个时候取消了同步,现在希望再恢复同步,没问题,DBMS_LOGSTDBY 家大业大,它还有个叫UNSKIP 的门生就是专干这个的。
DBMS_LOGSTDBY.UNSKIP (
stmt IN VARCHAR2,
schema_name IN VARCHAR2,
object_name IN VARCHAR2);
JSSLDG2> select *from dba_logstdby_skip;
ERROR STATEMENT_OPT OWNER NAME U E PROC
----- --------------- ---------- --------------- - - --------------------
N SCHEMA_DDL JSS TMP% Y
N DML JSS TMP% Y
N DML JSS TMP1 Y
........
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> execute dbms_logstdby.unskip('DML','JSS','TMP1'); --本步操作是为解决历史遗留问题,不用关注
PL/SQL 过程已成功完成。
JSSLDG2> executexecute dbms_logstdby.unskip('DML','JSS','TMP%');
PL/SQL 过程已成功完成。
JSSLDG2> execute
dbms_logstdby.unskip('SCHEMA_DDL','JSS','TMP%');
PL/SQL 过程已成功完成。
跳过同步已经取消了,紧接着我们需要再调用dbms_logstdby.instantiate_table 过程重新同步一下跳地的对象,将skip 这段时间,primary 对tmp1 表所做的操作同步过来(就俺看来,instantiate_table 过程实际上是借助dblink 重建了一遍对象),以保持与primary 的一致。Dbms_logstdby.instantiate_table 的语法如下:
DBMS_LOGSTDBY.INSTANTIATE_TABLE (
schema_name IN VARCHAR2,
table_name IN VARCHAR2,
dblink IN VARCHAR2);
JSSLDG2> EXECUTE DBMS_LOGSTDBY.INSTANTIATE_TABLE('JSS','TMP1','GETJSSWEB');
PL/SQL 过程已成功完成。
JSSLDG2> select *from jss.tmp1;
AA
--------------------
a
b
c
d
e
f
g
h
i
已选择9 行。
JSSWEB> insert into jss.tmp1 values ('j');
已创建1 行。
JSSWEB> insert into jss.tmp1 values ('k');
已创建1 行。
JSSWEB> commit;
提交完成。
JSSWEB> alter system switch logfile;
系统已更改。
JSSWEB> select max(sequence#) from v$archived_log;
MAX(SEQUENCE#)
--------------
877
JSSLDG2> alter database start logical standby apply immediate;
数据库已更改。
JSSLDG2> select sequence#,applied from dba_logstdby_log;
SEQUENCE# APPLIED
---------- --------
875 YES
876 YES
877 YES
JSSLDG2> select *from jss.tmp1;
AA
--------------------
a
b
c
d
e
f
g
h
i
j
k
已选择11 行。
四、特殊事件的控制
时间紧任务急,呵呵,这里三思就只描述流程,过程就不做演示了,相信你的智力,你一定能看懂。
SQL> ALTER SESSION DISABLE GUARD;
具体操作步骤可参考三思之前的笔记:使用可传输表空间的特性复制数据!
SQL> ALTER SESSION ENABLE GUARD;
同第二步。
※ create/alter/drop materialized view
※ create/alter/drop materialized view log
※ 对于逻辑standby 端建立的ON-COMMIT 物化视图会自动维护,ON-DEMAND 物化视图也还是需要手工调用dbms_mview.refresh 过程刷新。
※ 约束:由于约束在primary 已经检查过,因此standby 端不需要再次检查
※ 触发器:primary 端操作时结果被记录,在standby 端直接被应用。
※ 约束有效
※ 触发器有效
JSSLDG2> SELECT COUNT(*) AS IDLE_APPLIER FROM V$LOGSTDBY_PROCESS
2 WHERE TYPE = 'APPLIER' and status_code = 16166;
IDLE_APPLIER
------------
0
status_code = 16166 表示进程是空闲状态,可以看到"STATS"为"ORA-16116: no work available",当然空闲的applier 进程数为0 不一定代表应用应用非常繁忙,也有可能是因为当前没什么需要应用的日志,因此甚至应用进程都没启动:)
JSSLDG2> select name,value from v$logstdby_stats where name like 'TRANSACTION%';
NAME VALUE
--------------------- -------
transactions ready 896
transactions applied 871
ALTER DATABASE STOP LOGICAL STANDBY APPLY;
EXECUTE DBMS_LOGSTDBY.APPLY_SET('APPLY_SERVERS', 20);
ALTER DATABASE START LOGICAL STANDBYAPPLY IMMEDIATE;
需要调整preparer 进程数的机会不多,通常只有一种情况:applier 进程有空闲,transactions ready 还很多,但没有空闲的preparer 进程,这时候你可能需要增加一些preparer 进程。
SELECT COUNT(*) AS IDLE_PREPARER FROM V$LOGSTDBY_PROCESS WHERE TYPE ='PREPARER' and status_code = 16166;
select name,value from v$logstdby_stats where name like 'TRANSACTION%';
SELECT COUNT(*) AS IDLE_APPLIER FROM V$LOGSTDBY_PROCESS WHERE TYPE = 'APPLIER'and status_code = 16166;
ALTER DATABASE STOP LOGICAL STANDBY APPLY;
EXECUTE DBMS_LOGSTDBY.APPLY_SET('PREPARE_SERVERS', 4);
ALTER DATABASE START LOGICAL STANDBYAPPLY IMMEDIATE;
执行下列语句,查询当前LCR 可用的最大内存:
JSSLDG2> select * from v$logstdby_stats where name='maximum SGA for LCR cache';
NAME VALUE
------------------------------------ --------------------
maximum SGA for LCR cache 30
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> execute dbms_logstdby.apply_set('MAX_SGA',100);
PL/SQL 过程已成功完成。
JSSLDG2> alter database start logical standby apply immediate;
数据库已更改。
默认情况下逻辑standby 端事务应用顺序与primary 端提交顺序相同。
① 停止 sql 应用 :
SQL> ALTER DATABASE STOP LOGICAL STANDBYAPPLY;
② 允许事务不按照 primary 的提交顺序应用
SQL> EXECUTE DBMS_LOGSTDBY.APPLY_SET('PRESERVE_COMMIT_ORDER', 'FALSE');
③ 重新启动 sql 应用
SQL> ALTER DATABASE START LOGICAL STANDBYAPPLY IMMEDIATE;
① 还是先停止 sql 应用:
SQL> ALTER DATABASE STOP LOGICAL STANDBYAPPLY;
② 重置参数 PRESERVE_COMMIT_ORDER 的初始值:
SQL> EXECUTE DBMS_LOGSTDBY.APPLY_UNSET('PRESERVE_COMMIT_ORDER');
③ 重新启动 sql 应用:
SQL> ALTER DATABASE START LOGICAL STANDBYAPPLY IMMEDIATE;