Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
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
- Page 194 and 195: CHAPTER 4 ■ MEMORY STRUCTURES 149
- Page 196 and 197: CHAPTER 4 ■ MEMORY STRUCTURES 151
- Page 198 and 199: CHAPTER 4 ■ MEMORY STRUCTURES 153
- Page 200 and 201: CHAPTER 5 ■ ■ ■ Oracle Proces
- Page 202 and 203: CHAPTER 5 ■ ORACLE PROCESSES 157
- Page 204 and 205: CHAPTER 5 ■ ORACLE PROCESSES 159
- Page 206 and 207: CHAPTER 5 ■ ORACLE PROCESSES 161
- Page 208 and 209: CHAPTER 5 ■ ORACLE PROCESSES 163
- Page 210 and 211: CHAPTER 5 ■ ORACLE PROCESSES 165
- Page 212 and 213: CHAPTER 5 ■ ORACLE PROCESSES 167
- Page 214 and 215: CHAPTER 5 ■ ORACLE PROCESSES 169
- Page 216 and 217: CHAPTER 5 ■ ORACLE PROCESSES 171
- Page 218 and 219: CHAPTER 5 ■ ORACLE PROCESSES 173
- Page 220 and 221: CHAPTER 5 ■ ORACLE PROCESSES 175
- Page 222 and 223: CHAPTER 5 ■ ORACLE PROCESSES 177
- Page 224 and 225: CHAPTER 5 ■ ORACLE PROCESSES 179
- Page 226 and 227: CHAPTER 5 ■ ORACLE PROCESSES 181
- Page 228 and 229: CHAPTER 6 ■ ■ ■ Locking and L
- Page 230 and 231: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 232 and 233: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 234 and 235: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 236 and 237: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 238 and 239: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 240 and 241: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 242 and 243: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 246 and 247: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 248 and 249: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 250 and 251: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 252 and 253: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 254 and 255: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 256 and 257: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 258 and 259: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 260 and 261: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 262 and 263: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 264 and 265: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 266 and 267: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 268 and 269: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 270 and 271: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 272 and 273: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 274 and 275: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 276 and 277: CHAPTER 7 ■ ■ ■ Concurrency a
- Page 278 and 279: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 280 and 281: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 282 and 283: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 284 and 285: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 286 and 287: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 288 and 289: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 290 and 291: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 292 and 293: CHAPTER 7 ■ CONCURRENCY AND MULTI
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.