有一个Oracle数据库架构(数据非常小,但仍然有大约10-15个表)。它包含一种配置(路由表)。
有一个应用程序必须不时轮询此架构。不得使用通知。
如果架构中没有数据更新,则应用程序应使用其当前的内存中版本。
如果任何表有任何更新,应用程序应该将所有表重新加载到内存中。
从给定的关键点(时间或事务ID)开始,检查整个架构的最有效方法是什么?
我想象Oracle会为每个架构保留一个事务ID。然后应该有一种方法来查询这样的ID并保持与下次轮询比较。
我发现了这个问题,在行级别上存在这样的伪列:
How to find out when an Oracle table was updated the last time
我认为在架构级别上存在类似的东西。
有人可以指出我正确的方向吗?
答案 0 :(得分:12)
我不知道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;
这将导致您的应用程序在某种程度上序列化:需要调用此过程的每个语句都需要等到上一个语句完成。 “上次更新”表也可能不同步,因为即使激活触发器的更新被回滚,其上的更新也将保持不变。最后,如果您有特别长的交易,应用程序可以在交易完成之前获取新的日期/时间,从而违背目的。我越是想到这一点,它看起来就越糟糕。
避免这些问题的更好解决方案就是从触发器中插入一行。这不会锁定表,因此不会有任何序列化,并且不需要异步进行插入,因此它们可以与实际数据一起回滚(并且在应用程序之前不会显示数据也是可见的)。应用程序将获得max,如果表被索引,则应该非常快(实际上,此表将是索引组织表的理想候选者)。唯一的缺点是你需要一个定期运行的工作来清理旧值,所以它不会变得太大。
答案 1 :(得分:3)
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