Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Monitorowanie zmian w tabeli w Oracle

Replikacja bazy danych nie jest już ograniczona do konfiguracji Oracle-Oracle; Oracle-to-cloud i Oracle-to-BigQuery to tylko dwie z różnych opcji, które można teraz wybrać w konfiguracjach replikacji. W wielu z tych konfiguracji GoldenGate jest narzędziem z wyboru, biorąc pod uwagę jego wszechstronność i niezawodność. Niestety, podczas replikowania Oracle na inną platformę, działania takie jak modyfikacje tabeli mogą przeszkodzić w pracach. Dlatego pożądane byłoby śledzenie takich zmian w oczekiwaniu na obchodzenie się z ekstraktem GoldenGate z wdziękiem i szybko. Przyjrzyjmy się możliwym scenariuszom i określmy najlepszy kierunek działania.

Pierwszą myślą, jaką może mieć administrator DBA, jest ujednolicony audyt, ponieważ zapewnia on bogactwo informacji do działań podlegających audytowi. Niestety „tabela audytu” nie znajduje się na liście dostępnych uprawnień do audytu:

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 >

Co ciekawe, przywilej „ALTER ANY TABLE” jest podlega audytowi, ale nie kontroluje tego, co mogłoby zostać poddane audytowi:

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 > 

Taka polityka kontroluje tylko przyznawanie takich uprawnień innym użytkownikom i może nie zawsze generować rekord kontroli. Wymóg ten nie jest jeszcze spełniony przez audyty, więc należy opracować inne rozwiązanie. Na szczęście Oracle oferuje wyzwalacze na poziomie systemu, które mogą generować rekordy audytu dla takich działań. Przykład, jak można to zrobić, pokazano poniżej. Najpierw tworzona jest tabela zawierająca wygenerowane rekordy audytu:

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

Tabela jest indeksowana na obj_owner i operacji, aby przyspieszyć generowanie raportów. Następnie tworzony jest wyzwalacz jako użytkownik będący właścicielem monitorowanych tabel, aby rejestrować wszystkie wykonane instrukcje CREATE, ALTER i 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;
/

Ponieważ liczba 64-bajtowych „kawałków” tekstu SQL może być dość duża, wyzwalacz ogranicza kolumnę SQL_TEXT do pierwszych trzech „kawałków”, dzięki czemu maksymalna długość ciągu wynosi 192 znaki. Zgodnie z oczekiwaniami w przypadku większych instrukcji, pełny tekst nie zostanie dostarczony, ale powinien zawierać w całości wszystkie instrukcje „zmień tabelę”. Należy zauważyć, że ten wyzwalacz przechwyci nie tylko instrukcje ALTER TABLE, ale także wszelkie instrukcje CREATE/ALTER/DROP przesłane do bazy danych. Oznacza to, że polecenia alter user, alter trigger, alter package, alter function, alter tablespace, alter system, create… i drop… również są rejestrowane w tabeli DDL_LOG. Z tego powodu stół może szybko rosnąć i stać się dość duży, dlatego należy stworzyć plan zachowania skończonej historii. W przypadku większości systemów 90 dni powinno wystarczyć na śledzenie zmian w tabeli w bazie danych. Raporty wygenerowane na podstawie zarejestrowanych danych mogą być przechowywane przez dłuższy czas (na przykład 12 miesięcy), zanim zostaną usunięte.

Przykładowy skrypt do zarządzania danymi tabeli znajduje się poniżej; wymusza 90-dniowe okno danych. Tworzony jest katalog dziennika:

mkdir -p /u01/app/oracle/ddl_chg/purge_logs

Skrypt SQL został napisany w celu usunięcia starych rekordów z 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

To oczywiście nie może działać bezpośrednio z crona (lub podobnego harmonogramu), więc potrzebny jest skrypt opakowujący:

#!/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 {} ;

Skrypt powłoki ustawia odpowiednie środowisko i ORACLE_SID na podstawie danych wyjściowych polecenia ps. Skrypt będzie musiał zostać wyedytowany, aby podać nazwę bazy danych do przeszukania i lokalizację ORACLE_HOME. Można podać więcej niż jedną nazwę bazy danych za pomocą | jako separator:

'abd|def|ghi|jkl'

Zapewnia to sposób na wyczyszczenie tabeli DDL_LOG w każdej bazie danych, w której zainstalowano tę kombinację tabeli/wyzwalacza. Nazwa bazy danych jest zawarta w nazwie pliku dziennika, aby oddzielić ślady czyszczenia dla każdej bazy danych. Czas przechowywania plików dziennika można zmienić, aby spełnić ograniczenia pamięci monitorowanego systemu.

Raporty zmian można generować na podstawie danych znalezionych w tabeli 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

Nazwa bazy danych jest przekazywana do skryptu, więc zostanie uwzględniona w nazwie pliku raportu. Kod zgłasza tylko zmiany w tabeli (stąd długi ciąg zapytań UNION) i generuje raport podobny do tego pokazanego poniżej:

TAB_NAME         MODIFICATION                   MOD_TIME
---------------- ------------------------------ -----------------------------
SCOTT.DDL_LOG    modify sql_text varchar2(200)  23-NOV-19 01.23.49.859971 PM

Skrypt ustawia również formatowanie kolumn na podstawie maksymalnej długości przechowywanych danych, aby ewentualnie zmniejszyć długość wiersza. Dane znacznika czasu zostały użyte w celu dostarczenia zarówno daty, jak i widocznej wartości czasu dla wygenerowanych rekordów zmian. Skrypty te zostały przetestowane, ale mogą wymagać pewnych modyfikacji w oparciu o implementację dostawcy systemu operacyjnego Linux/Unix.

W przypadku administratorów baz danych, którzy nie używają zreplikowanych systemów, może to nie być przydatne. Jednak w przypadku osób replikujących dane z Oracle do innych systemów (takich jak BigQuery, Snowflake itp.) wiedza o tym, kiedy nastąpiły zmiany w tabelach, może ułatwić radzenie sobie z błędami replikacji spowodowanymi przez te zmiany. Im szybciej proces replikacji może wrócić na właściwe tory, tym szybciej systemy, które opierają się na tych zreplikowanych danych, mogą powrócić do funkcjonalności.

# # #

Zobacz artykuły Davida Fitzjarrella


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-12154 nie może rozpoznać podanego identyfikatora połączenia

  2. Jak włączyć rozszerzenia dla oci8 (Oracle) w php.ini - PHP Ostrzeżenie:Uruchomienie PHP:w nieznanym w wierszu 0

  3. Jak wyświetlić wynik/wyjście refcursora w Oracle SQL Developer?

  4. Pole logiczne w Oracle

  5. Jak używać kursora referencji Oracle z języka C# ODP.NET jako parametru ReturnValue bez użycia funkcji lub procedury przechowywanej?