Ça fait des mois que ce post traîne parmi les 70 sujets en cours de rédaction… presque fini mais pas encore tout à fait : Cette fois j’irai au bout !
Avertissement : Testez toujours les opérations que vous allez mettre en œuvre avec DBMS_REDEFINITION et ne prenez jamais comptant mes propos ! En particulier, notez que la majorité des tests de ce post ont été réalisés avec Oracle 11.1.0.6 sous Linux 32bits et que d’autres versions peuvent avoir des comportements différents.
DBMS_REDEFINITION est sans doute un des packages que j’utilise le plus, surtout depuis 10g et sa capacité à « redéfinir » (déplacer, reconstruire, transformer) une seule partition aussi facilement qu’une table avec 0 indisponibilité. Zéro ? quoique ! La faute aux utilisateurs qui ne veulent pas arrêter leur système ? Pas seulement, DBMS_REDEFINITION permet aussi de conserver plus de données en ligne en déplaçant des partitions sur autre type de stockage et sans passer le tablespace en lecture seule ni de manipuler ASM ou un Volume Manager comme Veritas.
Avant de dire de quoi parle ce post, je vous renvoie à ces 2 URLs. Notez que la première est vraiment bien faite :
- Oracle 11g Administrator’s Guide : Redefining Tables Online
- Oracle 11g PL/SQL Packages and Types Reference : DBMS_REDEFINITION
- Oracle 11g Reference : DBA_REDEFINITION_ERRORS et DBA_REDEFINITION_OBJECTS
Encore un petit conseil : Si vous trouvez que LiveReorg est puissant, regardez bien DBMS_REDEFINITION et d’autres outils comme le « split partition » et vous vous rendrez compte que vous pouvez faire pareil avec les licences EE !
Quelles sont les questions qu’il faut se poser quand vous utilisez ce package ? C’est justement de quoi ce post parle à travers un exemple simple et un ensemble de questions.
Question n°1 : Comment ça marche ?
Le principe de « redéfinition » d’une table ou une partition est très simple. Alors que votre table est accédée par des ordres DML, vous allez :
- Etape 1 : Votre table est en ligne
- Etape 2 : Démarrer la redéfinition, c’est à dire
- Créer une table vide dite « intermédiaire » avec vos nouvelles propriétés (PCTFREE, Nouveau Tablespace, Nouvelle taille de colonne ou tout ce que vous voulez ou presque)
- Définir des règles de correspondance entre les colonnes de votre table ou partition originale et la table cible (si les noms des colonnes ou les formats sont différents par exemple)
- Démarrer la capture, les modifications sur la table originale seront conservées dans un espace dédié pendant que la table intermédiaire sera alimentée par un select correspondant au moment du démarrage de la capture
- Etape 3 : Modification et synchronisation intermédiaire. Vous pouvez dans cette étape
- Construire automatiquement (ou manuellement) l’ensemble des contraintes, index, triggers et grants que vous voulez sur votre table intermédiaire. Ils seront conservés lors de l’étape 4.
- Synchroniser les modifications capturées pour diminuer le temps d’indisponibilité associé à l’étape 4
- Etape 4 : la bascule
- La table originale est verrouillée.
- Les noms de la table intermédiaire et la table ou partition originale sont échangés
- L’ensemble des clés étrangères et des triggers vers les 2 tables sont désactivés/activés à condition qu’ils aient été migrés automatiquement à l’étape 3.
- L’activité peu reprendre
L’étape 4 bloque avec un verrou exclusif la table/partition originale. Attention donc si l’application pour une raison ou une autre pose également des verrous qu’elle ne relâche pas ! Le temps d’indisponibilité si vous avez au préalable appliqué les modifications est assez cours et il n’est pas besoin de déconnecter les utilisateurs qui devront simplement attendre que l’opération d' »échange » de la table intermédiaire avec la table ou partition originale soit terminée.
Question n°2 : Doit-on vraiment utiliser DBMS_REDEFINITION ?
Surtout pas ! Enfin, s’il y a un moyen de faire autrement bien sur ! Pourquoi ?
- Parce que DBMS_REDEFINITION nécessite de dupliquer les données dans un autre espace pendant la durée de de l’opération. Un « alter table move » aussi, me direz vous !
- Parce que c’est plus compliqué qu’un « alter table move » !
- Parce que ça génère un surplus d’activité sur la table du fait de l’activation de la capture des changements pendant la phase de transition d’une table à l’autre
- Parce que c’est plus souvent inutile qu’on pense ! Quel est l’impact d’après vous de 10 000 « chained rows » dans une table pour votre application ? Et si ça vous gène, il est sans doute possible avec DELETE puis INSERT des lignes chaînées de les supprimer. Pour les repérer, utilisez l’ordre ANALYZE TABLE … CHAINED ROWS et faites attention aux foreign keys surtout avec ON DELETE CASCADE.
- Parce qu’il y a souvent des alternatives :
- SHRINK SPACE COMPACT est un bon exemple quand c’est utilisable.
- Vous pouvez faire des ONLINE MOVE sur une IOT !
- Vous pouvez peut-être persuader le métier d’arrêter son application
- Vous pouvez charger une valeur par défaut en batch dans une colonne que vous ajoutez
- Sûrement beaucoup d’autres cas que je n’imagine même pas
- Parce qu’il a des cas ou vous ne pouvez pas : Par exemple, si vous avez un Materialized View Log sur votre table ; remarquez qu’en 11g, ce cas n’est plus une limite d’après la documentation.
- Parce que vous n’utilisez pas la version « Enterprise Edition ». Désolé les amis ; et ça m’arrive aussi !
Maintenant que vous avez à peu prêt toutes les bonnes raisons de ne pas utiliser DBMS_REDEFINITION (J’en oublie ?), sachez vous pouvez les éliminer (ou non) et choisir d’utiliser ce package. Et ne dites pas : « Je n’utilise pas DBMS_REDEFINITION parce que c’est compliqué… Ce n’est pas vrai ! »
Question n°3 : Qu’est ce que vous voulez redéfinir ?
Cette question peut vous emmener loin… En réalité, même si, vous voulez redéfinir toute votre base de données (oubliez SYS et SYSTEM), il suffit de considérer que vous allez redéfinir séparément chacune de vos tables (ou partitions) et le problème devient très simple :
- Si après vous voulez vous organiser pour tout faire en même temps, parce que, par exemple votre application doit migrer simulta
nément pour gérer des colonnes plus grandes, c’est un autre problème. Dans ce cas vous terminerez la « redefinition » de toutes vos tables en même temps et en quelques minutes. Pour développer vos scripts, raisonnez table par table et partition par partition, ça sera très simple - Remarquez bien que :
- Les index et contraintes associées doivent être reconstruits avec la table. Ça peut être fait automatiquement par DBMS_REDEFINITION ou vous pouvez aussi les modifier manuellement
- Les triggers et les contraintes référentielles des autres tables vers cette table sont logés à la même enseigne que les index, sauf qu’ils seront activés lors de la dernière phase de l’opération si vous utilisez la gestion automatique des dépendances.
Remarque Importante : « Toute chose n’étant vrai que si son contraire l’est aussi (mon adage favori !) » : il y a des cas pour lesquels vous ne pourrez pas considérer votre problème comme un ensemble de sous problèmes indépendants et il faudra obligatoirement modifier un ensemble de tables/partitions simultanément. Par exemple :
- Si vous modifiez la taille et/ou le contenu d’une clé primaire référencée par une clé étrangère, vos devrez modifier l’ensemble des colonnes simultanément puisqu’elles sont dépendantes
- Si vous redéfinissez une table qui contient un LOB stocké dans une table overflow, il faudra redéfinir les 2 tables simultanément
- Si vous redéfinissez une partition d’une table avec des index globaux, ils seront « UNUSABLE » après l’échange des partitions
Question n°4 : La table/Partition doit-elle avoir une clé primaire ?
Il y a deux manières, pour DBMS_REDEFINITION, de suivre à quelle ligne s’applique une modification sur la table/partition originale :
- Soit avec la clé primaire (La solution que vous préférerez, sauf si ce n’est pas possible)
- Soit avec ROWID. Dans ce cas, une colonne (M_ROW$$) et un index (I_SNAP$_<TABLE_NAME>) seront ajoutés sur la table intermédiaire pour stocker et rechercher le ROWID. Cette deuxième méthode est donc plus consommatrice et créée une colonne qui est marquée NOT USED automatiquement si le paramètre COMPATIBLE est supérieur ou égal à 10.2.
La réponse est donc NON mais si votre table n’a pas de clé primaire, la méthode que vous utiliserez sera sans doute différentes.
Question n°5 : Puis-je vraiment utiliser DBMS_REDEFINITION avec ma table ?
Le meilleur moyen de le savoir, c’est de le demander. Pour ça, vous allez utiliser la procédure CAN_REDEF_TABLE. Pour cet exemple, nous allons modifier la table SCOTT.DEPT !
exec dbms_redefinition.can_redef_table(-
'SCOTT', -
'DEPT', -
DBMS_REDEFINITION.CONS_USE_PK)
PL/SQL procedure successfully completed.
Dans notre exemple, DBMS_REDEFINITION.CONS_USE_PK signifie que l’on veut s’appuyer sur la clé primaire. On pourrait, s’il n’y avait pas de clé primaire, s’appuyer sur le ROWID avec DBMS_REDEFINITION.CONS_USE_ROWID. Si vous ne pouvez pas redéfinir la table une erreur est retournée avec la raison associée.
Dans l’exemple qui suit on regarde s’il est possible de redéfinir la partition SALES.SALES_Q4_2003 du schéma exemple SH. Comme généralement les tables de fait ne sont pas de clé primaire, dans ce cas, on utilisera le ROWID. Notez que ce dernier exemple ne fonctionne qu’à partir de 10g :
exec dbms_redefinition.can_redef_table(-
'SH', -
'SALES', -
DBMS_REDEFINITION.CONS_USE_ROWID, -
'SALES_Q4_2003')
PL/SQL procedure successfully completed.
Question n°6 : Quelle doit être la structure de la table/partition intermédiaire que je vais créer ?
Vaste question ! Pourquoi vous voulez utiliser DBMS_REDEFINITION déjà ? Vous pouvez changer le type, le contenu, le nom des colonnes. Vous pouvez changez le tablespace, les clauses de stockage, les index, les triggers. Tout ce que vous voulez ! Je serai donc bien malin de vous dire comment doit être votre table à la fin.
Il faut toutefois noter quelques restrictions à la manière dont vous voulez que vos tables évoluent :
- Si vous ne réorganisez qu’une partition de la table, seules les clauses de stockage peuvent changer et vous ne pouvez pas changer une colonne de type par exemple !
- La relation entre les colonnes de la table d’origine et cible doit être simple et ne peut pas mettre en oeuvre des requetes SQL par exemple (Quoique!)
- Le plus simple pour faire évoluer votre table, c’est encore de capturer le DDL d’origine avec la commande DBMS_METADATA.GET_DDL comme ci-dessous :
var output clob;
exec :output:=dbms_metadata.get_ddl('TABLE',-
'EMP',-
'SCOTT')
set pages 1000
set long 9999
print output
OUTPUT
------------------------------------------------------------------------
CREATE TABLE "SCOTT"."DEPT" (
"DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS" ENABLE
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
Supposons donc que nous voulions créer une nouvelle table DEPT avec un PCT_FREE de 80, nous allons créer notre future « DEPT » table avec les informations que nous désirons voir modifiées et avec un nom différent (On pourra utiliser $INT pour dire qu’il s’agit d’une table intermédiaire) :
CREATE TABLE SCOTT.DEPT$INT (
DEPTNO NUMBER(2,0),
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT PK_DEPT$INT PRIMARY KEY (DEPTNO)
USING INDEX TABLESPACE USERS
) PCTFREE 80
TABLESPACE USERS;
Table created.
Question n°7 : Comment mettre en relation les colonnes de la table d’origine et les colonnes de la table modifiée ?
Et bien cette étape est réalisée lors de l’initialisation de la redéfinition grâce au paramètre COL_MAPPING de la procédure START_REDEF_TABLE. Et oui, l’étape suivante une fois que vous avez créé la table intermédiaire consiste à démarrer la redéfinition avec cette procédure; Si vous voulez changer le nom des c
olonnes ou transformer leur contenu, il faudra utiliser ce paramètre.
le contenu du paramètre peut être NULL ce qui indique que le nom et le contenu des colonnes ne change pas. Dans ce cas, le type peut changer à condition que les données soient compatibles avec le nouveau type. Si le paramètre COL_MAPPING n’est pas NULL, il doit alors indiquer le contenu de ce que serait une clause SELECT sur la table d’origine pour alimenter la table intermédiaire.
Dans notre cas, les colonnes restent identiques, nous pourrions utiliser NULL comme valeur pour le paramètre COL_MAPPING. Juste pour le geste, voila comment démarrer la redéfinition avec le paramètre positionné malgré tout :
exec DBMS_REDEFINITION.START_REDEF_TABLE( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
COL_MAPPING => 'deptno, dname, loc', -
options_flag =>
DBMS_REDEFINITION.CONS_USE_PK)
PL/SQL procedure successfully completed.
Cette opération, comme vous pouvez facilement le vérifier, démarre le chargement initial de la table intermédiaire :
select count(*)
from scott.dept$int
COUNT(*)
--------
4
Question n°8 : Comment créer les contraintes/index et autres objets dépendants ?
Vous pouvez copier les objets qui dépendent de votre table d’origine sur la table temporaire des maintenant ou après avoir commencé la redéfinition. A travers objets dépendants, on entend :
- Clé primaire ou secondaire (Remarquez que si vous vous appuyez sur une de ces clés, il faut qu’elle soit créées avant de commencer la redéfinition)
- Contrainte d’unicité et not null
- Check
- Clés étrangère à partir ou à destination de la table
- Index
- Triggers
- Grants
- (En 11g) Materialized View Logs
Pour ces opérations 3 possibilités mais notez que (1) Vous ne pouvez pas utiliser les méthodes automatiques ou enregistrer les objets dépendants tant que vous n’avez pas commencé la redéfinition; (2) vous ne pourrez pas créer de clés étrangères qui soit « enabled » (vous comprendrez facilement !) ; et (3), créer les index une fois la table alimentées peut avoir du sens en terme de performance. Les 3 possibilités sont donc :
- Créer manuellement les objets dépendants et gérer leur état manuellement (e.g : disable, validated…)
- Créer manuellement les objets dépendants et les mettre en correspondance avec les objets d’origine avec DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT
- Créer automatiquement les objets depuis la table d’origine avec la procédure DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS
Remarque importante : En 9i, vous ne disposez que de la première possibilité !
Dans l’exemple qui suit nous allons utiliser la méthode 3 pour créer automatiquement la clé étrangère entre EMP et DEPT$INT. Nous utiliserons la méthode 2 pour enregistrer manuellement la clé primaire PK_DEPT$INT parmi les objets dépendants. Notez que si vous ne le faite pas, la contrainte et l’index ne seront pas renommées à la fin de la redéfinition…
var numerr number;
exec DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(-
'SCOTT', -
'DEPT', -
'DEPT$INT', -
ignore_errors => true, -
num_errors => :numerr);
print numerr
NUMERR
------
2
La raison des 2 erreurs peut être facilement expliquée par le fait que nous avons créé une clé primaire et l’index associé lors de la création de la table. Pour cela, interrogeons DBA_REDEFINITION_ERRORS comme ci-dessous :
col OBJECT_TYPE format a15
col OBJECT_OWNER format a15
col OBJECT_NAME format a15
select OBJECT_TYPE,
OBJECT_OWNER,
OBJECT_NAME,
DDL_TXT
from dba_redefinition_errors
OBJECT_TYPE OBJECT_OWNER OBJECT_NAME
------------ --------------- ---------------
DDL_TXT
--------------------------------------------------------------------------------
INDEX SCOTT PK_DEPT
CREATE UNIQUE INDEX "SCOTT"."TMP$$_PK_DEPT0" ON "SCOTT"."DEPT$INT" ("DEPTNO")
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
CONSTRAINT SCOTT PK_DEPT
ALTER TABLE "SCOTT"."DEPT$INT" ADD CONSTRAINT "TMP$$_PK_DEPT0" PRIMARY KEY ("DEP
TNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS" ENABLE NOVALIDATE
Pour connaître les objets qui sont maintenant gérés par DBMS_REDEFINITION, vous pouvez interroger la vue DBA_REDEFINITION_OBJECTS :
col TYPE format a10
col OWNER format a6
col NAME format a9
col IOWNER format a6
col INAME format a16
select OBJECT_TYPE TYPE,
OBJECT_OWNER OWNER,
OBJECT_NAME NAME,
INTERIM_OBJECT_OWNER IOWNER,
INTERIM_OBJECT_NAME INAME
from dba_redefinition_objects;
TYPE OWNER NAME IOWNER INAME
---------- ------ --------- ------ ----------------
TABLE SCOTT DEPT SCOTT DEPT$INT
CONSTRAINT SCOTT FK_DEPTNO SCOTT TMP$$_FK_DEPTNO0
Enfin, il est possible d’ajouter la clé primaire et l’index créés avant le démarrage de la redéfinition à l’aide de DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT comme ci-dessous :
exec dbms_redefinition.register_dependent_object( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
DBMS_REDEFINITION.CONS_INDEX, -
'SCOTT', -
'PK_DEPT', -
'PK_DEPT$INT');
PL/SQL procedure successfully completed.
exec dbms_redefinition.register_dependent_object( -
'SCOTT', -
'DEPT', -
'DEPT$INT', -
DBMS_REDEFINITION.CONS_CONSTRAINT, -
'SCOTT', -
'PK_DEPT', -
'PK_DEPT$INT');
PL/SQL procedure successfully completed.
select OBJECT_TYPE TYPE,
OBJECT_OWNER OWNER,
OBJECT_NAME NAME,
INTERIM_OBJECT_OWNER IOWNER,
INTERIM_OBJECT_NAME INAME
from dba_redefinition_objects;
TYPE OWNER NAME IOWNER INAME
---------- ------ --------- ------ ----------------
TABLE SCOTT DEPT SCOTT DEPT$INT
CONSTRAINT SCOTT FK_DEPTNO SCOTT TMP$$_FK_DEPTNO0
INDEX SCOTT PK_DEPT SCOTT PK_DEPT$INT
CONSTRAINT SCOTT PK_DEPT SCOTT PK_DEPT$INT
Et nous voila fin prêt pour la suite…
Question n°9 : Comment faire des synchronisations intermédiaires ?
Cette question peut paraître saugrenue mais dans la réalité, reconstruire l’ensemble des dépendance peut être long et beaucoup de transactions peuvent être appliquées sur la table d’origine pendant la phase précédente… Pour réduire le temps de transition, ou simplement pour améli
orer vos phases de tests, faire des synchronisation intermédiaire, y compris juste avant de basculer la table intermédiaire avec la table/partition d’origine sont une bonne pratique. Pour cela, vous allez utiliser la procédure DBMS_REDEFINITION.SYNC_INTERIM_TABLE comme ci-dessous :
exec dbms_redefinition.sync_interim_table( -
'SCOTT', -
'DEPT', -
'DEPT$INT')
PL/SQL procedure successfully completed.
Il est facile de voir l’effet de cette fonction, si par exemple, vous avez inséré, modifié ou supprimé une ligne entre le début de l’utilisation de DBMS_REDEFINITION et le moment de la synchronisation intermédiaire.
Question n°10 : Que se passe-t-il si on a des transactions en cours lorsque l’on finit d’utiliser DBMS_REDEFINITION ?
Pour répondre à cette question, nous allons terminer la redéfinition avec DBMS_REDEFINITION.FINISH_REDEF_TABLE, mais avant, nous allons ouvrir une nouvelle session SQL*Plus et exécuter l’ordre suivant (En veillant à laisser la session ouverte)
select *
from scott.dept
where deptno=10
for update;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
Et, comme prévu, nous allons terminer, à partir d’une autre session la redefinition
exec dbms_redefinition.finish_redef_table( -
'SCOTT', -
'DEPT', -
'DEPT$INT')
Heureusement avec SQL*Plus il est simple d’abandonner la procédure car, l’intention de poser un verrou exclusif sur la table est donnée et les nouvelles transactions sont bloquées. J’appuie vite sur
*
ERROR at line 1:
ORA-42012: error occurred while completing the redefinition
ORA-01013: user requested cancel of current operation
ORA-06512: at "SYS.DBMS_REDEFINITION", line 78
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1664
ORA-06512: at line 1
C’est pour cette raison qu’il est sans doute préférable :
- De superviser les verrous posés depuis longtemps avant de terminer une redéfinition
- D’utiliser un LOCK TABLE … IN EXCLUSIVE MODE WAIT 3 avant d’utiliser une commande comme celle-ci.
Annulez l’ordre SELECT FOR UPDATE de votre session blocante :
rollback;
Rollback complete.
Puis dans la seconde session, executez DBMS_REDEFINITION.FINISH_REDEF_TABLE avec le lock exclusive wait dans le même block PL/SQL:
begin
lock table scott.dept in exclusive mode wait 3;
dbms_redefinition.finish_redef_table(
'SCOTT',
'DEPT',
'DEPT$INT');
end;
/
PL/SQL procedure successfully completed.
Bon en l’occurence dbms_redefinition.finish_table_redef opère un ordre DDL qui libère le lock TM pose par la commande LOCK TABLE mais en général, n’hésitez pas à ajoutez la commande rollback avant la fin de votre code PL/SQL
Question n°11 : Qu’est-ce qui peut changer après l’utilisation de DBMS_REDEFINITION et quel peut-être l’impact de ces changements ?
Je n’ai pas trouvé de documentation officielle à ce sujet mais voilà au moins ce à quoi il faut être attentif. Il se peut que j’en oublie alors soyez attentif à tout et dites moi si vous trouvez autre chose (même le plus petit détails comme un droit !)
A) Si vous faites des changements sur les objets dépendants et que vous ne gérez pas la transition via DBMS_REDEFINITION (Ce qui est toujours le cas avant 10g), il faut gérer manuellement ces objets et en particulier il faut activer (ENABLE) :
- Les triggers
- Les contraintes
- Les Materialized View Log
D’autres part, vous noterez également que les statistiques ne sont pas importées et que les objets intérimaires gardent leur nom (Vous pouvez le renommer manuellement).
B) Si vous faites les changements sur les objets dépendant via DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS, il faut noter que les contraintes sont « NO VALIDATED » et que, j’en ai déjà parlé, ça peut avoir un impact sur les plans d’exécution. N’hésitez pas à les valider dès que vous le pouvez (Immediatement pour NOT NULL, plus tard pour les FK…)
C) Si vous utilisez la redéfinition avec le ROWID, une colonne qui contient le rowid est ajoutée a la table. Faites y d’autant plus attention si COMPATIBLE<=10.1 puisque un "SELECT *" ne ramenera pas le même nombre de colonnes. Enfin avec COMPATIBLE >= 10.2, ce n’est plus le cas et la colonne est masquée mais elle est toujours là ! Vous pouvez toujours la supprimée après coup.
D) En 9i au moins, les statistiques et dans tous les cas bien sur les structures physiques. Il n’est pas improbable que cette opération aboutisse à des changements de plan d’exécution, souvent recherchés et parfois non
F) Les objets dépendant sont invalidés (vues, packages PL/SQL) et selon l’utilisation qui en est faite, il est possible voir probable que votre application rencontre des erreurs lors de l’appel de FINISH_TABLE_REDEF !
Question n°12 : Est-ce terminé ?
En fait, non ! N’oubliez pas de supprimer la table intermédiaire qui est en fait la table d’origine que vous n’utilisez plus ainsi que toutes ses dépendances :
drop table scott.dept$int
cascade constraints
purge;
Table dropped.
Question n°13 : Comment recommencer de zéro ?
Si pour n’importe quelle raison, vous devez arrêter en cours de route la redéfinition de vos objets, utilisez la fonction DBMS_REDEFINITION.ABORT_REDEF_TABLE. Vous pourrez alors supprimer tous les objets intermédiaires créés et recommencer de zéro ou pas !
Question n°14 : A quoi faire attention encore ?
En arrière plan, lorsque commence une redéfinition, la table intermédiaire devient une vue matérialisée de la table d’origine et un « MV Log » est ajoutée à la table d’origine en mode « fast refresh ». Vous en déduirez simplement comment suivre l’évolution des captures sur la table d’origine ! Voila et même si, comme moi, vous avez une confiance aveugle en Oracle, il est sans doute préférable de comparer l’ensemble des informations dont vous disposez avant et aprè
s les modifications et surtout de tester que votre application supporte bien de tels changements.
Voila c’est tout pour l’instant ! Si jamais j’avais oublié d’autres différences générées par DBMS_REDEFINITION (cf question 11), n’hésitez pas à commenter ce post ! A part ça, je souhaite simplement que ce post puisse vous servir d’aide mémoire pour la prochaine utilisation de ce package.
2 réflexions sur “2-3 trucs à propos de DBMS_REDEFINITION”
Vous pouvez utiliser oem grid control qui fait tous les checks et génère le script
Vous avez éclairé ma lanterne quant à l’emploi du package DBMS_REDEFINITION pour faire des Reorg Online de tables.
C’est ( quand même ) une technique très importante – et utile – pour les environnements de Production avec contrainte de disponibilité … peut-être insuffisamment documentée et « intégrée » selon moi.
Votre synthèse – qui plus est en français – mes semble complète et présente bien les enjeux et limitations de la technique.
Je vais tester par moi-même : étant un peu inquiet par d’éventuelles invalidations de vues ou packages que vous indiquez
( une gestion automatique de ces « objets dépendants » par le DBMS_REDEFINITION serait bienvenue … » ).
Olivier
Les commentaires sont fermés.