データベースのレプリケーションは、OracleからOracleへの構成に制限されなくなりました。 Oracle-to-cloudとOracle-to-BigQueryは、レプリケーション構成で選択できるさまざまなオプションの2つにすぎません。これらの構成の多くには、その汎用性と信頼性を考慮して、GoldenGateが最適なツールとして存在します。残念ながら、Oracleを別のプラットフォームに複製する場合、テーブルの変更などのアクションにより、モンキーレンチが動作する可能性があります。したがって、GoldenGate抽出物の異常終了を適切かつ迅速に処理することを見越して、このような変更を追跡することが望ましいでしょう。考えられるシナリオを見て、最善の行動方針を決定しましょう。
DBAが最初に考えたのは、監査可能なアクションに関する豊富な情報を提供する統合監査です。残念ながら、「監査テーブル」は、監査に使用できる特権のリストには含まれていません。
SCOTT @ orcl > create audit policy alter_tab_pol 2 privileges alter table; privileges alter table * ERROR at line 2: ORA-46355: missing or invalid privilege audit option. SCOTT @ orcl >
興味深いことに、「ALTERANYTABLE」特権は 監査可能ですが、監査されると思われるものは監査されません:
SCOTT @ orcl > create audit policy table_pol 2 privileges create any table, alter any table, drop any table; Audit policy created. SCOTT @ orcl > audit policy table_pol; Audit succeeded. SCOTT @ orcl >
そのようなポリシーは、他のユーザーへのそのような特権の付与を監査するだけであり、常に監査レコードを生成するとは限りません。要件は監査によってまだ満たされていないため、別のソリューションを作成する必要があります。幸い、Oracleは、そのようなアクションの監査レコードを生成できるシステムレベルのトリガーを提供しています。これがどのように行われるかの例を以下に示します。最初に、生成された監査レコードを含むテーブルが作成されます。
create table ddl_log ( operation varchar2(30), obj_owner varchar2(35), object_name varchar2(35), sql_text varchar2(200), attempt_by varchar2(35), attempt_dt timestamp); create index ddl_log_idx on ddl_log(obj_owner, operation);
テーブルはobj_ownerと操作でインデックス付けされ、レポートの生成を高速化します。次に、実行されたすべてのCREATE、ALTER、およびDROPステートメントをログに記録するために、監視対象のテーブルを所有するユーザーとしてトリガーが作成されます。
create or replace trigger ddl_trigger before create or alter or drop on schema declare oper ddl_log.operation%type; sql_text ora_name_list_t; i pls_integer; begin i := sql_txt(sql_text); if i = 1 then insert into ddl_log select ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1), user, v_systimestamp from dual; elsif i = 2 then insert into ddl_log select ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1)||sql_text(2), user, v_systimestamp from dual; elsif i >= 3 then insert into ddl_log select ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1)||sql_text(2)||sql_text(3), user, v_systimestamp from dual; end if; end ddl_trigger; /
SQLテキストの64バイトの「ピース」の数は非常に多くなる可能性があるため、トリガーはSQL_TEXT列を最初の3つの「ピース」に制限し、文字列の最大長を192文字にします。より大きなステートメントで予想されるように、完全なテキストは提供されませんが、「altertable」ステートメント全体をキャプチャする必要があります。このトリガーは、ALTER TABLEステートメントだけでなく、データベースに送信されたCREATE / ALTER/DROPステートメントもキャプチャすることに注意してください。これは、ユーザーの変更、トリガーの変更、パッケージの変更、関数の変更、テーブルスペースの変更、システムの変更、…およびドロップ…ステートメントの作成もDDL_LOGテーブルに記録されることを意味します。このため、テーブルが急速に大きくなり、非常に大きくなる可能性があるため、有限の履歴を維持するための計画を作成する必要があります。ほとんどのシステムでは、データベース内のテーブルの変更を追跡するには90日で十分です。ログに記録されたデータから生成されたレポートは、削除される前に長期間(たとえば、12か月)保持できます。
テーブルデータを管理するためのサンプルスクリプトを以下に示します。 90日間のデータウィンドウを適用します。ログディレクトリが作成されます:
mkdir -p /u01/app/oracle/ddl_chg/purge_logs
SQLスクリプトは、DDL_LOGから古いレコードを削除するように記述されています:
column sys_date new_value dt noprint column name new_value db_nm noprint select to_char(sysdate,'RRRRMMDD') sys_date from dual; select name from v$database; spool /u01/app/oracle/ddl_chg/purge_logs/ddl_log_purge_$db_nm._&dt..log set echo on -- -- Records slated for removal -- select * From ddl_log where attempt_dt < sysdate - 90; -- -- Delete selected records -- delete from ddl_log where attempt_dt < sysdate - 90; commit; spool off set echo off
これは明らかに、cron(または同様のスケジューラ)から直接実行できないため、ラッパースクリプトが必要です:
#!/bin/ksh # # purge_ddl_log_90.sh # # Shell script to purge old audit records # from the DDL_LOG table # # # Find the selected database and set the environment # set -A database `ps -ef | grep [p]mon | grep '<name>' | awk -F"_" '{print $3}'` for i in ${database[@]} # # Set the environment for the database # do ORACLE_SID=$i export ORACLE_SID ORAENV_ASK=NO export ORAENV_ASK unset ORACLE_BASE export ORACLE_BASE PATH=$PATH:<ORACLE_HOME/bin location> . <ORACLE_HOME/bin>/oraenv -s LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib:$ORACLE_HOME/precomp/public export LD_LIBRARY_PATH PATH=$ORACLE_HOME/bin:$PATH export PATH # # Start SQL*Plus and execute the script # sqlplus /nolog <<EOF connect / as sysdba @/u01/app/oracle/ddl_chg/purge_ddl_log_90.sql EOF done # # Make the output files readable for all * cd /u01/app/oracle/ddl_chg/purge_logs chmod 666 *.log # # Remove old purge logs # find . -name "purge*log" -mtime +365 -exec /bin/rm -rf {} ;
シェルスクリプトは、psコマンドの出力に基づいて適切な環境とORACLE_SIDを設定します。スクリプトを編集して、検索するデータベース名とORACLE_HOMEの場所を指定する必要があります。 |を使用して複数のデータベース名を指定できます。セパレータとして:
'abd|def|ghi|jkl'
これにより、このテーブルとトリガーの組み合わせがインストールされているすべてのデータベースのDDL_LOGテーブルをパージする方法が提供されます。データベース名はログファイル名に含まれ、データベースごとにパージトレイルを個別に保持します。ログファイルを保持する時間の長さは、監視対象のシステムのストレージ制限を満たすように変更できます。
変更レポートは、DDL_LOGテーブルにあるデータから生成できます:
set linesize 140 column sdate new_value sdt noprint select to_Char(sysdate, 'RRRRMMDDHH24')sdate from dual; column modlen new_value mlen noprint select 'a'||nvl(max(length(modification)),25) modlen From (select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'modify ')) modification, attempt_dt mod_time from ddl_log where (instr(sql_text, 'alter table') > 0 or instr(sql_text, 'ALTER TABLE') > 0)); column objlen new_value olen noprint select 'a'||nvl(max(length(owner||'.'||tabname)),60) objlen From (select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'modify ')) modification, attempt_dt mod_time from ddl_log where (instr(sql_text, 'alter table') > 0 or instr(sql_text, 'ALTER TABLE') > 0)); column modification format &mlen column mod_time format a29 column tab_name format &olen select owner||'.'|| tabname tab_name, modification, mod_time from (select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'add ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0 union select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'drop ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0 union select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'modify ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0 union select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'ADD ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0 union select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'DROP ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0 union select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'MODIFY ')) modification, attempt_dt mod_time from ddl_log where instr(lower(sql_text), 'alter table') > 0) dl where lower(dl.modification) not like '%table%' and mod_time >= trunc(systimestamp) order by 1, 3 spool /u01/app/oracle/ddl_chg/log/tab_chg_rpt_&sdt._&1..lst / spool off
データベース名はスクリプトに渡されるため、レポートファイル名に含まれます。このコードは、テーブルの変更のみをレポートし(したがって、UNIONクエリの長い文字列)、以下に示すようなレポートを生成します。
TAB_NAME MODIFICATION MOD_TIME ---------------- ------------------------------ ----------------------------- SCOTT.DDL_LOG modify sql_text varchar2(200) 23-NOV-19 01.23.49.859971 PM
また、スクリプトは、保存されたデータの最大長に基づいて列のフォーマットを設定し、行の長さを減らす可能性があります。タイムスタンプデータは、生成された変更レコードの日付と表示時間の両方の値を提供するために使用されました。これらのスクリプトはテスト済みですが、オペレーティングシステムベンダーによるLinux / Unixの実装に基づいて、いくつかの変更が必要になる場合があります。
複製されたシステムを実行していないDBAの場合、これはあまり役に立たない可能性があります。ただし、Oracleから他のシステム(BigQuery、Snowflakeなど)にデータを複製する場合は、テーブルの変更がいつ発生したかを知ることで、それらの変更によって作成された複製の失敗に対処しやすくなります。レプリケーションプロセスがより速く軌道に戻ることができるほど、そのレプリケートされたデータに依存するシステムがより速く機能に戻ることができます。
###
David Fitzjarrellの記事を見る