如何在Oracle中使用Timestamp_to_scn和Scn_to_timestamp?

Mon*_*hon 11 sql oracle datetime timestamp oracle-sqldeveloper

作为查询的结果,我有这个:

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
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用函数timestamp_to_scn将此时间戳转换为scn时,我收到以下错误:

ORA-08180:未找到基于指定时间ORA-06512的快照:在"SYS.TIMESTAMP_TO_SCN",第1行08180. 00000 - "未根据指定时间找到快照"*原因:无法与SCN的时间相匹配映射表.*行动:尝试使用更长的时间.

当我在ora_rowscn上使用scn_to_timestamp将该列转换为时间戳时,我收到以下错误:

ORA-08181:指定的编号不是有效的系统更改编号ORA-06512:在"SYS.SCN_TO_TIMESTAMP",第1行08181. 00000 - "指定的编号不是有效的系统更改编号"*原因:提供的scn超出了界限一个有效的scn.*动作:使用有效的scn.

我做错了什么?

Ale*_*ole 20

你试图看得太远了.您只能转换为系统维护的重做/闪回窗口中的SCN.一旦更改老化,映射就会丢失.

在文档中解释:

数据库在一段有限的时间内记住SCN与生成SCN时的时间戳之间的关联.如果数据库以自动撤消管理模式运行,则此期间是自动调整的撤消保留期的最大值,以及数据库中所有闪回存档的保留时间,但不少于120小时.只有在数据库打开时,关联才会过时.如果为参数指定的SCN SCN_TO_TIMESTAMP太旧,则会返回错误.

请记住,这些是Oracle内部机制的一部分,因此对我们的使用有限; 虽然它们对闪回查询当然很有用 - 再次在同一个窗口内.


Dmi*_*y.M 6

当某些事件发生时,SCN_TO_TIMESTAMP 使用一些内部算法来完成 SCN 和 TIME 之间的映射,并且它以良好的近似值完成工作。但有一个限制。如果 UNDO 数据不包括您的时期,您就不能回溯太久。

在这种情况下,当您达到撤消数据的限制时,有一种棘手的方法可以创建我们自己的映射。它不会像 SCN_TO_TIMESTAMP 那样好,但它会根据您的数据提供近似值。

您需要做的就是找到一个不断进行插入的表。我使用审计表sys.aud$。您可以使用自己的表,但表必须有时间记录,指示插入行的时间。如果您有 SCN 和 DATE,则可以将 SCN 和 DATE 映射到另一个表。

如果您将使用sys.aud$ 请记住:

  1. 您可能需要 dba 授予对其的访问权限或创建一个包含两个字段 ora_rowscn 和 ntimestamp# 的简单视图#
  2. 数据库上进行的活动越多,映射就越准确。通常使用 sys.aud$ 表,我可以映射一年前发生的旧数据编辑,准确度约为 60-120 分钟
  3. 如果审计关闭,则 scn_time 将不会返回任何行,您需要找到另一个表进行映射。

该查询使用 sys.aud$。将[YOU_TABLE]替换为您需要查找插入或更新日期的表

-- 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
Run Code Online (Sandbox Code Playgroud)

如果插入的行是一年多前的,我使用了插入行时恢复信息的方法。