??? 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;