Oracle中如何使用Timestamp_to_scn和Scn_to_timestamp?

Posted

技术标签:

【中文标题】Oracle中如何使用Timestamp_to_scn和Scn_to_timestamp?【英文标题】:How to use Timestamp_to_scn and Scn_to_timestamp in Oracle? 【发布时间】:2014-05-06 01:51:43 【问题描述】:

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

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

但是当我尝试使用函数 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。

我做错了什么?

【问题讨论】:

【参考方案1】:

你试图回望太远。您只能与系统维护的重做/闪回窗口中的 SCN 相互转换。一旦更改过期,映射就会丢失。

这是解释in the documentation:

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

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

【讨论】:

非常感谢@Alex。 :)【参考方案2】:

将 UNDO_MANAGEMENT 设置为 AUTO,并将 UNDO_RETENTION 设置为将涵盖您最长查询时间段的值。还要设置 RETENTION GARANTEE 以防止 UNDO 被覆盖。

对于 Oracle 10g,您的闪回时间不能超过 5 天。这是一个硬编码限制。 对于 Oracle 11g,没有限制。

【讨论】:

【参考方案3】:

当某些事件发生时,SCN_TO_TIMESTAMP 使用一些内部算法来进行 SCN 和 TIME 之间的映射,并且它以很好的近似值完成了这项工作。但是有一个限制。如果 UNDO 数据不涵盖您的经期,您就不能在过去走得太远。

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

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

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

    您可能需要您的 dba 授予对它的访问权限或创建一个包含两个字段 ora_rowscn 和 ntimestamp# 的简单视图 数据库上的活动越多,映射就越准确。通常使用 sys.aud$ 表,我可以映射一年前发生的旧数据编辑,准确度约为 60-120 分钟 如果审计关闭,那么 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

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

【讨论】:

以上是关于Oracle中如何使用Timestamp_to_scn和Scn_to_timestamp?的主要内容,如果未能解决你的问题,请参考以下文章

在oracle中如何结合使用('')和like

oracle中如何使用级联

Oracle中如何在储过程中使用临时表

如何查看oracle失效的索引

oracle如何列出特定存储过程中使用的所有表

oracle存储过程中循环for in是如何使用的