Cet article est la traduction d’un article de Tom Kyte sur son blog (L’article original en anglais se trouve ici).
Lectures cohérentes et multi-versionnage, par Tom Kyte
Il est conseillé lire préalablement les premières partie:
- Ecritures cohérentes, par Tom Kyte (1ère partie)
- Ecritures cohérentes – observation d’un redémarrage (2ème partie)
La première chose qui vient à l’esprit, c’est que le trigger se déclenche deux fois. On avait une table avec une seule ligne, et un trigger BEFORE FOR EACH ROW qui se déclanche pour chaque ligne. Un a fait un update sur une seule ligne et le trigger s’est déclanché deux fois.
Vous devez penser aux conséquentes de cela. Si vous faites dans votre trigger quoi que ce soit qui ne soit pas transactionnel, vous pouvez avoir un problème assez sérieux.
Par exemple, imaginez un trigger qui envoie un e-mail avec dans le texte de l’e-mail quelque chose comme: « Voilà comment étaient les données, elles ont été mises à jour et voici la nouvelle valeur. » Si cet e-mail est envoyé directement à partir du trigger, en utilisant UTL_SMTP sous Oracle 9i ou UTL_MAIL depuis Oracle 10g, alors le destinataire va recevoir deux e-mails, dont un qui avertit d’une mise à jour qui n’a jamais eu lieu.
L’update restart a un impact dans tout ce que vous pouvez faire de non-transactionnel dans un trigger. Réflechissez aux consequences suivantes:
- Prenons un trigger qui maintient quelques variables globales PL/SQL, du genre le nombre de lignes traitées. Lorsque un update qui redémarre fait son rollback, les modifications faites sur les variables PL/SQL ne sont pas rollbackées, elles.
- Pratiquement toutes les fonctions qui commencent par UTL_ (UTL_FILE, UTL_HTTP, UTL_SMTP etc) doivent être vues comme sensibles à un redémarrage de requête. Lors du redémarrage, ULT_FILE ne va pas revenir sur ce qu’il a écrit dans le fichier.
- Un trigger qui fait partie d’une transaction autonome (autonomous transaction) doit être suspect. Lorsque la requête redémarre, la transaction autonome ne peut pas être rollbackée.
Toutes ces conséquence doivent être gérées avec attention, en prenant compte du fait qu’elles peuvent être déclenchées plus d’une fois par ligne, ou être déclenchées par une ligne qui n’est au final pas modifiée par la requête.
La deuxième raison pour laquelle vous devez prêter attention aux redémarrages potentiels est une raison de performance. Dans notre exemple, nous avons utilisé une table avec une seule ligne. Mais qu’arrive-t-il si vous lancez un update de toute une table et qu’il redémarre après avoir mis à jour les 100000 premiers enregistrements ? Il va faire un rollback des 100000 modifications, redémarrer en mode SELECT FOR UPDATE, puis refaire à nouveau les 100000 modifications.
Vous pourriez remarquer une dégradation des performance au delà de ce que vous attendiez, après avoir mis un simple trigger qui trace toutes les mises à jour à l’aide de :old et :new. Et ce serait parce vous avez des requête qui redémarrent alors que ce n’était pas le cas avant. Ou bien l’ajout d’un tout petit programme qui fait un update d’une seule une ligne, et qui fait qu’un batch se met à durer des heures à cause d’un restart qui n’avait pas lieu avant.
Ce n’est pas une nouvelle fonctionnalité d’Oracle. Çà existe depuis la version 4.0, lorsque la lecture cohérente (read consistency a été introduite. Je n’étais moi-même pas au courant de cela avant l’été 2003, et lorsque j’ai découvert les conséquences, j’ai pu amener des réponses a des questions que je m’étais posé dans le passé.
Çà m’a fait jurer de renoncer presque complètement au transactions autonomes dans les triggers, et à repenser la manière dont j’avais implémenté certaines de mes applications. Par exemple, je ne vais jamais envoyer un e-mail directement à partir d’un trigger, mais plutôt utiliser DBMS_JOB qui va l’envoyer après que ma transaction soit commitée. Cela rend transactionnel l’envoi d’e-mail car si la requête qui a déclanché le trigger doit être redémarrée, alors le rollback va aussi annuler la soumission du job par DBMS_JOB.
J’ai modifié tout ce qui n’était pas transactionnel dans les triggers pour le faire dans un job, afin de le rendre transactionnellement cohérent.
Le livre en Anglais de Tom Kyte dont est extrait l’article original:
Expert Oracle Database Architecture: 9i and 10g Programming Techniques and Solutions
Apress (September 15, 2005)La seconde édition (mise à jour avec la 11g) va paraître bientôt.