La réplication de base de données n'est plus limitée aux configurations d'Oracle à Oracle; Oracle vers cloud et Oracle vers BigQuery ne sont que deux des différentes options qui peuvent désormais être sélectionnées pour les configurations de réplication. Dans bon nombre de ces configurations, GoldenGate est l'outil de choix, compte tenu de sa polyvalence et de sa fiabilité. Malheureusement, lors de la réplication d'Oracle sur une autre plate-forme, des actions telles que des modifications de table peuvent jeter une clé à molette dans les travaux. Ainsi, il serait souhaitable de suivre ces changements en prévision de la gestion des extraits abends GoldenGate avec élégance et rapidité. Examinons les scénarios possibles et déterminons le meilleur plan d'action.
La première pensée que le DBA pourrait avoir est l'audit unifié, car il fournit une mine d'informations pour des actions auditables. Hélas 'table d'audit' ne fait pas partie de la liste des privilèges disponibles pour auditer :
SCOTT @ orcl> créer une politique d'audit alter_tab_pol 2 privilèges alter table;privileges alter table *ERREUR à la ligne 2 :ORA-46355 :option d'audit de privilège manquante ou invalide.SCOTT @ orcl>
Fait intéressant, le privilège "ALTER ANY TABLE" est auditable, mais il n'audite pas ce que vous pensez être audité :
SCOTT @ orcl> créer une politique d'audit table_pol 2 privilèges créer n'importe quelle table, modifier n'importe quelle table, supprimer n'importe quelle table;Politique d'audit créée.SCOTT @ orcl> politique d'audit table_pol;Audit réussi.SCOTT @ orcl>
Une telle stratégie audite uniquement l'octroi de tels privilèges à d'autres utilisateurs et peut ne pas toujours produire un enregistrement d'audit. L'exigence n'est pas encore satisfaite par l'audit, une autre solution doit donc être produite. Heureusement, Oracle propose des déclencheurs au niveau du système qui peuvent produire des enregistrements d'audit pour de telles actions. Un exemple de la façon dont cela pourrait être fait est illustré ci-dessous. Une table est d'abord créée pour contenir les enregistrements d'audit générés :
créer la table ddl_log (opération varchar2(30),obj_owner varchar2(35),object_name varchar2(35),sql_text varchar2(200),attempt_by varchar2(35),attempt_dt timestamp); créer l'index ddl_log_idx sur ddl_log(obj_owner, operation);
La table est indexée sur obj_owner et operation pour accélérer la génération du rapport. Ensuite, un déclencheur est créé en tant qu'utilisateur propriétaire des tables à surveiller pour consigner toutes les instructions CREATE, ALTER et DROP qui ont été exécutées :
créer ou remplacer le déclencheur ddl_triggeravant de créer ou de modifier ou de supprimer le schémadeclare oper ddl_log.operation%type ; sql_text ora_name_list_t ; je pls_integer ; commencer je :=sql_txt(sql_text); si je =1, insérez dans ddl_log sélectionnez ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1), user, v_systimestamp from dual ; elsif i =2 puis insérez dans ddl_log sélectionnez ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1)||sql_text(2), user, v_systimestamp from dual ; elsif i>=3 puis insérez dans ddl_log sélectionnez ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, sql_text(1)||sql_text(2)||sql_text(3), user, v_systimestamp from dual ; fin si;fin ddl_trigger;/
Étant donné que le nombre de "morceaux" de 64 octets du texte SQL peut être assez important, le déclencheur limite la colonne SQL_TEXT aux trois premiers "morceaux", ce qui fait que la longueur maximale de la chaîne est de 192 caractères. Comme prévu pour les déclarations plus volumineuses, le texte complet ne sera pas fourni, mais il devrait saisir toutes les déclarations « modifier la table » dans leur intégralité. Notez que ce déclencheur capturera non seulement les instructions ALTER TABLE, mais également toute instruction CREATE/ALTER/DROP soumise à la base de données. Cela signifie que les instructions alter user, alter trigger, alter package, alter function, alter tablespace, alter system, create… et drop… sont également consignées dans la table DDL_LOG. Pour cette raison, la table peut croître rapidement et devenir assez grande, donc un plan pour garder un historique fini doit être créé. Pour la plupart des systèmes, 90 jours devraient être suffisants pour suivre les changements de table dans la base de données. Les rapports générés à partir des données enregistrées peuvent être conservés plus longtemps (par exemple, 12 mois) avant d'être supprimés.
Un exemple de script pour gérer les données du tableau est fourni ci-dessous ; il applique une fenêtre de données de 90 jours. Un répertoire de journaux est créé :
mkdir -p /u01/app/oracle/ddl_chg/purge_logs
Un script SQL est écrit pour purger les anciens enregistrements de DDL_LOG :
column sys_date new_value dt noprintcolumn name new_value db_nm noprintselect 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.. logset echo on---- Records devant être supprimés--select * From ddl_log where try_dtCeci, évidemment, ne peut pas s'exécuter directement à partir de cron (ou de tout planificateur similaire), donc un script wrapper est nécessaire :
#!/bin/ksh## purge_ddl_log_90.sh## Script shell pour purger les anciens enregistrements d'audit# de la table DDL_LOG### Trouvez la base de données sélectionnée et définissez l'environnement#set -A database `ps -ef | grep [p]mon | grep '' | awk -F"_" '{print $3}'`for i in ${database[@]}## Définir l'environnement pour la base de données#do ORACLE_SID=$i export ORACLE_SID ORAENV_ASK=NO export ORAENV_ASK unset ORACLE_BASE export ORACLE_BASE PATH=$PATH: . /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## Démarrez SQL*Plus et exécutez le script# sqlplus /nolog < Le script shell définit l'environnement et ORACLE_SID appropriés en fonction de la sortie de la commande ps. Le script devra être modifié pour fournir le nom de la base de données à rechercher et l'emplacement ORACLE_HOME. Plus d'un nom de base de données peut être spécifié en utilisant | comme séparateur :
'abd|def|ghi|jkl'Cela permet de purger la table DDL_LOG dans chaque base de données où cette combinaison table/déclencheur a été installée. Le nom de la base de données est inclus dans le nom du fichier journal pour garder les pistes de purge séparées pour chaque base de données. La durée de conservation des fichiers journaux peut être modifiée pour respecter les limites de stockage du système surveillé.
Des rapports de modification peuvent être générés à partir des données présentes dans la table DDL_LOG :
set linesize 140column sdate new_value sdt noprintselect to_Char(sysdate, 'RRRRMMDDHH24')sdate from dual;column modlen new_value mlen noprintselect 'a'||nvl(max(length(modification)),25) modellen From(select obj_owner owner , nom_objet tabname, substr(sql_text, instr(sql_text, 'modify ')) modification, tentative_dt mod_timefrom ddl_logwhere (instr(sql_text, 'alter table')> 0or instr(sql_text, 'ALTER TABLE')> 0));column objlen new_value olen noprintselect 'a'||nvl(max(length(owner||'.'||tabname)),60) objlen From(select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'modify ') ) modification, tentative_dt mod_timefrom ddl_logwhere (instr(sql_text, 'alter table')> 0or instr(sql_text, 'ALTER TABLE')> 0));format de modification de colonne &mlencolumn format mod_time a29column tab_name format &olenselect owner||'.'|| tabname tab_name, modification, mod_timefrom(select obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'add ')) modification, try_dt mod_timefrom ddl_logwhere instr(lower(sql_text), 'alter table')> 0unionselect obj_owner owner, object_name tabname, substr(sql_text, instr(sql_text, 'drop ')) modification, tentative_dt mod_timefrom ddl_logwhere instr(lower(sql_text), 'alter table')> 0unionselect obj_owner propriétaire, object_name tabname, substr(sql_text, instr(sql_text, 'modify ')) modification, tentative_dt mod_timefrom ddl_logwhere instr(lower(sql_text), 'alter table')> 0unionselect obj_owner propriétaire, object_name tabname, substr(sql_text, instr(sql_text, 'ADD ')) modification, tentative_dt mod_timefrom ddl_logwhere instr(lower( sql_text), 'alter table')> 0unionselect obj_owner propriétaire, object_name tabname, substr(sql_text, instr(sql_text, 'DROP ')) modification, tentative_dt mod_timefrom ddl_logwhere instr(lower(sql_text), 'alter table')> 0unionselect obj_owner propriétaire , objet _name tabname, substr(sql_text, instr(sql_text, 'MODIFY ')) modification, try_dt mod_timefrom ddl_logwhere instr(lower(sql_text), 'alter table')> 0) dlwhere lower(dl.modification) not like '%table%' et mod_time>=trunc(systimestamp)order by 1, 3spool /u01/app/oracle/ddl_chg/log/tab_chg_rpt_&sdt._&1..lst/spool offLe nom de la base de données est transmis au script afin qu'il soit inclus dans le nom du fichier de rapport. Le code ne signale que les modifications de table (d'où la longue chaîne de requêtes UNION) et produit un rapport similaire à celui présenté ci-dessous :
TAB_NAME MODIFICATION MOD_TIME---------------- ---------------------------- -- ------------------------SCOTT.DDL_LOG modifier sql_text varchar2(200) 23-NOV-19 01.23.49.859971 PMLe script définit également le formatage des colonnes en fonction de la longueur maximale des données stockées pour éventuellement réduire la longueur de la ligne. Les données d'horodatage ont été utilisées afin de fournir à la fois des valeurs de date et d'heure visibles pour les enregistrements de modification générés. Ces scripts ont été testés mais peuvent nécessiter certaines modifications en fonction de l'implémentation de Linux/Unix par le fournisseur du système d'exploitation.
Pour les DBA qui n'exécutent pas de systèmes répliqués, cela peut ne pas être d'une grande utilité. Mais, pour ceux qui répliquent des données d'Oracle vers d'autres systèmes (tels que BigQuery, Snowflake, etc.), savoir quand des modifications de table se sont produites peut faciliter la gestion des échecs de réplication créés par ces modifications. Plus vite le processus de réplication peut se remettre sur les rails, plus vite les systèmes qui s'appuient sur ces données répliquées peuvent revenir à la fonctionnalité.
# # #
Voir les articles de David Fitzjarrell