Question

Some research into checking when a table's records were last updated, modified, or deleted has lead me to the pseudo column known as ora_rowscn.

First, I do this:

select max(ora_rowscn) from tablename;

I take note of the number. Then I do an insert, update, and a delete, check that max value before and after each. It appears to increment for each type of change.

If you're wondering why I am doing this, we cache a list of entities in our C# windows service. This service runs on two load-balanced servers, so there's a separate instance of each running. When an update occurs on server A, server B needs to know about it. What I want to do is cache max(ora_rowscn) into a variable. Every time our application goes to insert, update, or delete a record, it will get a new max from the database. If the value is different then it obviously knows it needs to go get a new list from the database.

So my actual question is this: Are there any other snags I should be aware of that might result in an insert, update, or deletion of a record not incrementing this value?

Edit: Can someone add ora_rowscn as a tag?

Was it helpful?

Solution

Are there any other snags I should be aware of that might result in an insert, update, or deletion of a record not incrementing this value?

ora_rowscn is always incremented when a row changes - but in a default configuration it can also be incremented when a row does not change

If you need to check the whole table for udates, one method is to use auditing. On the other hand if you only need to check the row you are trying to update for conflicts, ora_rowscn with rowdependencies is ideal.

OTHER TIPS

Getting the max(ora_rowscn) will require a full table scan each time you do it. It may be faster just to refresh the entire cache each time.

It sounds like you need a way to notify the other service that a change took place and what the change was. You could maintain a log table with a column that indicates which system needs to consume the change. The column could have two function based indexes one for each service so that each index contains only the entries that need to be consumed. Then as they are consumed they can make the value NULL to remove it from the index.

Or you could just use Oracle's Advanced Queuing.

As @Leigh Riffel noted, a select max(ora_rowscn) will result in a full table scan. An alternative is to have a timestamp column (we will call sys_ts for this example) which is populated to the time of statement execution (which is not the same as statement commitment, which is when the scn is generated/populated). An index on the sys_ts column will allow you to look at the most recent x (say 25) rows to find the max ora_rowscn only from those rows.

The most straight forward way to do this would be to use the rownum to limit results as described in this[1] ask tom article:

select *
from (select sys_ts, ora_rowscn
from table order by SYS_TS desc) where rownum < 25;

Unfortunately, that also results in a full table scan (at least in oracle 11.2.0.3). This has been reported to Oracle, but determined not to be a defect (bug 17347125).

This requires a bit more work to achieve effectively the same result:

select b.sys_ts,b.ora_rowscn from
    (select rid from 
        (select rowid as rid from table order by sys_ts desc) 
    where rownum <= 25) a, table b
where a.rid = b.rowid;

[1] - http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top