Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 6 ■ LOCKING AND LATCHING 199 The only modified ORA_ROWSCN at this point belongs to DEPTNO = 10, exactly what we wanted. We can now rely on ORA_ROWSCN to detect row-level changes for us. CONVERTING AN SCN TO WALL CLOCK TIME There is another benefit of the transparent ORA_ROWSCN column: we can convert an SCN into wall clock time approximately (within about +/–3 seconds) to discover when the row was last modified. So, for example, I can do this: ops$tkyte@ORA10G> select deptno, ora_rowscn, scn_to_timestamp(ora_rowscn) ts 2 from dept; DEPTNO ORA_ROWSCN TS ---------- ---------- ------------------------------- 10 34676381 25-APR-05 02.37.04.000000000 PM 20 34676364 25-APR-05 02.34.42.000000000 PM 30 34676364 25-APR-05 02.34.42.000000000 PM 40 34676364 25-APR-05 02.34.42.000000000 PM Here you can see that I waited almost three minutes in between the initial creation of the table and the update of DEPTNO = 10. However, this translation of an SCN to a wall clock time has definite limits: about five days of database uptime. For example, if I go to an “old” table and find the oldest ORA_ROWSCN in it (note that I’ve logged in as SCOTT in this case; I am not using the new table from earlier): scott@ORA10G> select min(ora_rowscn) from dept; MIN(ORA_ROWSCN) --------------- 364937 If I try to convert that SCN into a timestamp, I might find the following (depending on how old the DEPT table is!): scott@ORA10G> select scn_to_timestamp(min(ora_rowscn)) from dept; select scn_to_timestamp(min(ora_rowscn)) from dept * ERROR at line 1: ORA-08181: specified number is not a valid system change number ORA-06512: at "SYS.SCN_TO_TIMESTAMP", line 1 ORA-06512: at line 1 So that conversion cannot be relied on in the long term.

200 CHAPTER 6 ■ LOCKING AND LATCHING Optimistic or Pessimistic Locking? So which method is best? In my experience, pessimistic locking works very well in Oracle (but perhaps not in other databases) and has many advantages over optimistic locking. However, it requires a stateful connection to the database, like a client/server connection. This is because locks are not held across connections. This single fact makes pessimistic locking unrealistic in many cases today. In the past, with client/server applications and a couple dozen or hundred users, it would have been my first and only choice. Today, however, optimistic concurrency control is what I would recommend for most applications. Having a connection for the entire duration of a transaction is just too high a price to pay. Of the methods available, which do I use? I tend to use the version column approach with a timestamp column. It gives me the extra information “when was this row last updated” in a long-term sense. So it adds value in that way. It is less computationally expensive than a hash or checksum, and it doesn’t run into the issues potentially encountered with a hash or checksum when processing LONG, LONG RAW, CLOB, BLOB, and other very large columns. If I had to add optimistic concurrency controls to a table that was still being used with a pessimistic locking scheme (e.g., the table was accessed in both client/server applications and over the Web), I would opt for the ORA_ROWSCN approach. The reason is that the existing legacy application might not appreciate a new column appearing, or even if we took the additional step of hiding the extra column, we might not appreciate the overhead of the necessary trigger to maintain it. The ORA_ROWSCN technique would be nonintrusive and lightweight in that respect (well, after we get over the table re-creation, that is). The hashing/checksum approach is very database independent, especially if we compute the hashes or checksums outside of the database. However, by performing the computations in the middle tier rather than the database, we will incur higher resource usage penalties, in terms of CPU usage and network transfers. Blocking Blocking occurs when one session holds a lock on a resource that another session is requesting. As a result, the requesting session will be blocked—it will “hang” until the holding session gives up the locked resource. In almost every case, blocking is avoidable. In fact, if you do find that your session is blocked in an interactive application, then you have probably been suffering from the lost update bug as well, perhaps without realizing it. That is, your application logic is flawed and that is the cause of the blocking. The five common DML statements that will block in the database are INSERT, UPDATE, DELETE, MERGE, and SELECT FOR UPDATE. The solution to a blocked SELECT FOR UPDATE is trivial: simply add the NOWAIT clause and it will no longer block. Instead, your application will report back to the end user that the row is already locked. The interesting cases are the remaining four DML statements. We’ll look at each of them and see why they should not block and how to correct the situation if they do. Blocked Inserts There are few times when an INSERT will block. The most common scenario is when you have a table with a primary key or unique constraint placed on it and two sessions attempt to insert a row with the same value. One of the sessions will block until the other session either commits (in which case the blocked session will receive an error about a duplicate value) or rolls

CHAPTER 6 ■ LOCKING AND LATCHING 199<br />

The only modified ORA_ROWSCN at this point belongs to DEPTNO = 10, exactly what we<br />

wanted. We can now rely on ORA_ROWSCN to detect row-level changes for us.<br />

CONVERTING AN SCN TO WALL CLOCK TIME<br />

There is another benefit of the transparent ORA_ROWSCN column: we can convert an SCN into wall clock<br />

time approximately (within about +/–3 seconds) to discover when the row was last modified. So, for<br />

example, I can do this:<br />

ops$tkyte@ORA10G> select deptno, ora_rowscn, scn_to_timestamp(ora_rowscn) ts<br />

2 from dept;<br />

DEPTNO ORA_ROWSCN TS<br />

---------- ---------- -------------------------------<br />

10 34676381 25-APR-05 02.37.04.000000000 PM<br />

20 34676364 25-APR-05 02.34.42.000000000 PM<br />

30 34676364 25-APR-05 02.34.42.000000000 PM<br />

40 34676364 25-APR-05 02.34.42.000000000 PM<br />

Here you can see that I waited almost three minutes in between the initial creation of the table <strong>and</strong> the<br />

update of DEPTNO = 10. However, this translation of an SCN to a wall clock time has definite limits: about<br />

five days of database uptime. For example, if I go to an “old” table <strong>and</strong> find the oldest ORA_ROWSCN in it (note<br />

that I’ve logged in as SCOTT in this case; I am not using the new table from earlier):<br />

scott@ORA10G> select min(ora_rowscn) from dept;<br />

MIN(ORA_ROWSCN)<br />

---------------<br />

364937<br />

If I try to convert that SCN into a timestamp, I might find the following (depending on how old the DEPT<br />

table is!):<br />

scott@ORA10G> select scn_to_timestamp(min(ora_rowscn)) from dept;<br />

select scn_to_timestamp(min(ora_rowscn)) from dept<br />

*<br />

ERROR at line 1:<br />

ORA-08181: specified number is not a valid system change number<br />

ORA-06512: at "SYS.SCN_TO_TIMESTAMP", line 1<br />

ORA-06512: at line 1<br />

So that conversion cannot be relied on in the long term.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!