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 中查找表上次截断的时间?包含该信息的任何系统表