Oracle:如何在模式中找到上次更新(任何表)的时间戳?

Posted

技术标签:

【中文标题】Oracle:如何在模式中找到上次更新(任何表)的时间戳?【英文标题】:Oracle: How to find the timestamp of the last update (any table) within a schema? 【发布时间】:2011-10-10 04:18:50 【问题描述】:

有一个 Oracle 数据库模式(数据非常少,但仍有大约 10-15 个表)。它包含一种配置(路由表)。

有一个应用程序必须不时轮询此架构。不得使用通知。

如果架构中的数据未更新,则应用程序应使用其当前的内存版本。

如果任何表有任何更新,应用程序应将所有表重新加载到内存中。

自给定关键点(时间或事务 ID)以来,检查整个架构以进行更新的最有效方法是什么?

我想象 Oracle 为每个模式保留一个事务 ID。那么应该有一种方法可以查询这样的 ID 并保留它以在下次投票时进行比较。

我发现了这个问题,这样的伪列存在于行级别:

How to find out when an Oracle table was updated the last time

我认为架构级别存在类似的东西。

有人可以指点我正确的方向吗?

【问题讨论】:

您是在谈论对架构本身 (DDL) 的更改还是对表中数据的更新? 数据变化,不清楚的地方见谅。 【参考方案1】:

我不知道 Oracle 中有任何此类功能。见下文。

我能想出的最佳解决方案是在每个表上创建一个触发器,用当前日期/时间更新单行表或context。这样的触发器可以在表级(而不是行级),因此它们不会像大多数触发器那样承担太多的开销。

顺便提一下,Oracle 不能为每个架构保留一个事务 ID,因为一个事务可能会影响多个架构。或许可以使用 V$ 视图将事务跟踪回它所影响的对象,但这并不容易,而且几乎肯定会比触发方案执行得更差。

事实证明,如果你有 10g,你可以使用 Oracle 的闪回功能来获取这些信息。但是,您需要启用闪回(这会带来一些自己的开销)并且查询速度非常慢(可能是因为它并不是真正打算用于此用途):

select max(commit_timestamp) 
from FLASHBACK_TRANSACTION_QUERY 
where table_owner = 'YOUR_SCHEMA' 
      and operation in ('INSERT','UPDATE','DELETE','MERGE') 

为了避免“最后更新”表中的锁定问题,您可能希望将该更新放入使用自治事务的过程中,例如:

create or replace procedure log_last_update as
pragma autonomous_transaction;
begin
   update last_update set update_date = greatest(sysdate,update_date);
   commit;
end log_last_update;

这将导致您的应用程序在某种程度上序列化:需要调用此过程的每个语句都需要等到前一个语句完成。 “上次更新”表也可能不同步,因为即使激活触发器的更新被回滚,其上的更新也会持续存在。最后,如果您有一个特别长的交易,应用程序可能会在交易完成之前获取新的日期/时间,从而达到目的。我越想这个,就越觉得这是个坏主意。


避免这些问题的更好解决方案是从触发器中插入一行。这不会锁定表,因此不会有任何序列化并且插入不需要异步进行,因此它们可以与实际数据一起回滚(并且直到您的应用程序不可见数据也是可见的)。应用程序将获得最大值,如果表被索引,这应该非常快(事实上,该表将是索引组织表的理想候选者)。唯一的缺点是您需要定期运行以清除旧值的作业,因此它不会变得太大。

【讨论】:

好主意。但请记住,如果您使用闪回,则必须密切注意保留设置。即使这样,如果服务器重新启动,数据更改也可能会丢失。您可能需要使用 Oracle Total Recall 之类的工具来真正保证捕获所有更改。 关于触发器:使用并行更新,更新单行表时如何避免冲突?有没有办法说“此更新超出了当前事务”? 感谢触发器方法的详细解释。当前应用程序中的更新并不频繁,而且很短(添加路由,删除路由),因此序列化行为不是问题。不同步也不是问题:最坏的情况可能是额外的配置重新加载,这(如果只是偶尔发生)不会造成任何伤害。我将首先使用触发器进行更新。谢谢!【参考方案2】:

dbms_stats.gather_table_stats 也可能有帮助:http://forums.oracle.com/forums/thread.jspa?threadID=607610

   4. Statistics is considered to be stale, when the change is over 10% of current rows. 
   (As of 11g, this value can be customized per objects. Cool feature)


    .
    . 
    .

exec dbms_stats.gather_table_stats(user, 'T_STAT');

select * from sys.dba_tab_modifications where table_name = 'T_STAT';
No row selected

select stale_stats from sys.dba_tab_statistics where table_name = 'T_STAT';
NO

insert into t_stat select rownum from all_objects where rownum <= 20;

select * from sys.dba_tab_modifications where table_name = 'T_STAT';
No rows selected <-- Oops
select stale_stats from sys.dba_tab_statistics where table_name = 'T_STAT';
NO  <-- Oops

exec dbms_stats.flush_database_monitoring_info;

select * from sys.dba_tab_modifications where table_name = 'T_STAT';
TABLE_OWNER TABLE_NAME  PARTITION_NAME  SUBPARTITION_NAME   INSERTS UPDATES DELETES TIMESTAMP   TRUNCATED   DROP_SEGMENTS
UKJA        T_STAT      20  0   0   2008-01-18 PM 11:30:19  NO  0

select stale_stats from sys.dba_tab_statistics where table_name = 'T_STAT';
YES

【讨论】:

以上是关于Oracle:如何在模式中找到上次更新(任何表)的时间戳?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Sybase 中查找表上次截断的时间?包含该信息的任何系统表

Hive - 如何在 Hive 中跟踪和更新增量表的上次修改日期?

如何在Oracle中多次更新与另一个表连接的表?

在 oracle 数据库的所有表中更新与特定模式匹配的列

PHP Mysql获取表上次更新时间和日期[重复]

如何根据oracle中另一个表中的值更新一个表中的字段[重复]