web-dev-qa-db-fra.com

Comment utiliser Timestamp_to_scn et Scn_to_timestamp dans Oracle?

J'ai ceci à la suite de la requête:

select cast(to_date(a.start_time,'mm/dd/yyyy hh:mi:ss pm') as timestamp) date_of_call,
ora_rowscn from calling_table a where rownum <= 10;

       DATE_OF_CALLING          ORA_ROWSCN

26-JUL-13 12.29.28.000000000 PM 8347567733892
26-JUL-13 12.29.35.000000000 PM 8347567733892
26-JUL-13 12.29.35.000000000 PM 8347567733892
26-JUL-13 12.29.38.000000000 PM 8347567733892
26-JUL-13 12.29.44.000000000 PM 8347567733892
26-JUL-13 12.29.47.000000000 PM 8347567733892
26-JUL-13 12.29.48.000000000 PM 8347567733892
26-JUL-13 12.29.48.000000000 PM 8347567733892
26-JUL-13 12.29.48.000000000 PM 8347567733892
26-JUL-13 12.29.56.000000000 PM 8347567733892

Mais lorsque j'essaie de convertir cet horodatage en scn en utilisant la fonction timestamp_to_scn, j'obtiens l'erreur suivante:

ORA-08180: aucun instantané trouvé en fonction de l'heure spécifiée ORA-06512: à "SYS.TIMESTAMP_TO_SCN", ligne 1 08180. 00000 - "aucun instantané trouvé en fonction de l'heure spécifiée" * Cause: Impossible de faire correspondre l'heure à un SCN à partir du table de mappage. * Action: essayez d'utiliser un temps plus long.

Et lorsque j'utilise scn_to_timestamp sur ora_rowscn pour convertir cette colonne en horodatage, j'obtiens l'erreur suivante:

ORA-08181: le numéro spécifié n'est pas un numéro de changement de système valide ORA-06512: à "SYS.SCN_TO_TIMESTAMP", ligne 1 08181. 00000 - "le numéro spécifié n'est pas un numéro de changement de système valide" * Cause: le scn fourni dépassait les limites d'un scn valide. * Action: utilisez un scn valide.

Qu'est-ce que je fais mal?

13
MontyPython

Vous essayez de regarder trop loin en arrière. Vous ne pouvez convertir que vers et depuis des SCN qui se trouvent dans la fenêtre de rétablissement/flashback gérée par votre système. Une fois que les modifications ont expiré, le mappage est perdu.

Ceci est expliqué dans la documentation :

L'association entre un SCN et un horodatage lorsque le SCN est généré est mémorisée par la base de données pendant une période de temps limitée. Cette période est le maximum de la période de rétention d'annulation automatique, si la base de données s'exécute en mode de gestion d'annulation automatique, et les temps de rétention de toutes les archives de flashback dans la base de données, mais pas moins de 120 heures. Le temps pour que l'association devienne obsolète ne s'écoule que lorsque la base de données est ouverte. Une erreur est renvoyée si le SCN spécifié pour l'argument à SCN_TO_TIMESTAMP est trop vieux.

Gardez à l'esprit que ceux-ci font partie du mécanisme interne d'Oracle et sont donc d'une utilité limitée pour nous; bien qu'ils soient utiles pour les requêtes flashback bien sûr - à nouveau dans la même fenêtre.

22
Alex Poole

SCN_TO_TIMESTAMP utilise des algorithmes internes pour effectuer le mappage entre SCN et TIME lorsqu'un événement s'est produit et il fait le travail avec une bonne approximation. Mais il y a une limite. Vous ne pouvez pas aller trop loin dans le passé si les données UNDO ne couvrent pas votre période.

Dans ce cas, il existe un moyen délicat de créer notre propre mappage lorsque vous atteignez une limite de données d'annulation. Il ne sera pas aussi bon que SCN_TO_TIMESTAMP mais il fournira une approximation en fonction de vos données.

Tout ce que vous avez à faire est de trouver une table avec des insertions constantes. J'utilise la table d'audit sys.aud $. Vous pouvez utiliser le vôtre, mais le tableau doit avoir une heure de classement indiquant quand les lignes ont été insérées. Et si vous avez SCN et DATE, vous pouvez mapper SCN et DATE avec une autre table.

Si vous utilisez sys.aud $ gardez à l'esprit que:

  1. Vous pouvez avoir besoin de votre dba pour y accéder ou pour créer une vue simple avec deux champs ora_rowscn et ntimestamp #
  2. plus il y a d'activité sur la base de données, plus la cartographie sera précise. En utilisant généralement la table sys.aud $, je peux cartographier les anciennes modifications de données qui se sont produites il y a un an avec une précision d'environ 60 à 120 minutes.
  3. si l'audit est désactivé, scn_time ne renverra aucune ligne et vous devez trouver une autre table pour le mappage.

La requête utilise sys.aud $. Remplacez [YOU_TABLE] par le tableau où vous devez trouver la date d'insertion ou de mise à jour

-- get scn to date interval [begin..end] mapping from audit table      
with scn_time as
 (
     select sc sc_start, 
            lead(sc) over(order by sc) sc_end,
            start_time,
            lead(end_time) over(order by sc) end_time_sc
     from 
      (
        select n.ora_rowscn sc, 
        min( cast(from_tz(ntimestamp#,'00:00') at local as date) ) start_time,
        max( cast(from_tz(ntimestamp#,'00:00') at local as date) ) end_time
            from sys.aud$ n
            -- if audit log is big you need to select only a part of the table
            -- to make query faster
            --where ntimestamp# > sysdate - 365
           group by  n.ora_rowscn 
      ) order by sc 
  )
-- map scn from you table to scn_mapping  
select *
  from (
          select t.ora_rowscn sc, t.*
          from [YOU_TABLE] t
       ) table_inspect
 inner join scn_time s
    on (table_inspect.sc between s.sc_start and s.sc_end)
 -- to filter out bit intervals    
 where (end_time_sc-start_time) < 1

J'ai utilisé le moyen de restaurer les informations lorsqu'une ligne a été insérée si elle a été insérée il y a plus d'un an.

3
Dmitry.M

Définissez UNDO_MANAGEMENT sur AUTO et UNDO_RETENTION sur une valeur qui couvrira la période de votre requête la plus longue dans le temps. Réglez également GARANTIE DE RETENTION pour éviter que UNDO ne soit écrasé.

Pour Oracle 10g, vous ne pouvez pas faire de flashback de plus de 5 jours. Il s'agit d'une limite codée en dur. Pour Oracle 11g, il n'y a aucune limitation.

2
xDBA