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 7 ■ CONCURRENCY AND MULTI-VERSIONING 235 Now, our select statement starts executing and reads row 1, row 2, and so on. At some point while we are in the middle of the query, a transaction moves $400.00 from account 123 to account 987. This transaction does the two updates, but does not commit. The table now looks as shown in Table 7-3. Table 7-3. ACCOUNTS Table During Modifications Row Account Number Account Balance Locked? 1 123 ($500.00) changed to $100.00 X 2 456 $240.25 . . . . . . . . . 342,023 987 ($100.00) changed to $500.00 X So, two of those rows are locked. If anyone tried to update them, that user would be blocked. So far, the behavior we are seeing is more or less consistent across all databases. The difference will be in what happens when the query gets to the locked data. When the query we are executing gets to the block containing the locked row (row 342,023) at the “bottom” of the table, it will notice that the data in the row has changed since the time at which it started execution. To provide a consistent (correct) answer, Oracle will at this point create a copy of the block containing this row as it existed when the query began. That is, it will read a value of $100.00, which is the value that existed at the time the query began. Effectively, Oracle takes a detour around the modified data—it reads around it, reconstructing it from the undo (also known as a rollback) segment (discussed in detail in Chapter 9). A consistent and correct answer comes back without waiting for the transaction to commit. Now, a database that allowed a dirty read would simply return the value it saw in account 987 at the time it read it, in this case $500.00. The query would count the transferred $400 twice. Therefore, it not only returns the wrong answer, but also returns a total that never existed in the table at any point in time. In a multiuser database, a dirty read can be a dangerous feature and, personally, I have never seen the usefulness of it. Say that, rather than transferring, the transaction was actually just depositing $400.00 in account 987. The dirty read would count the $400.00 and get the “right” answer, wouldn’t it? Well, suppose the uncommitted transaction was rolled back. We have just counted $400.00 that was never actually in the database. The point here is that dirty read is not a feature; rather, it is a liability. In Oracle, it is just not needed. You get all of the advantages of a dirty read (no blocking) without any of the incorrect results. READ COMMITTED The READ COMMITTED isolation level states that a transaction may only read data that has been committed in the database. There are no dirty reads. There may be nonrepeatable reads (i.e., rereads of the same row may return a different answer in the same transaction) and phantom reads (i.e., newly inserted and committed rows become visible to a query that were not visible earlier in the transaction). READ COMMITTED is perhaps the most commonly used isolation level in database applications everywhere, and it is the default mode for Oracle databases. It is rare to see a different isolation level used.

236 CHAPTER 7 ■ CONCURRENCY AND MULTI-VERSIONING However, achieving READ COMMITTED isolation is not as cut-and-dried as it sounds. If you look at Table 7-1, it appears straightforward. Obviously, given the earlier rules, a query executed in any database using the READ COMMITTED isolation will behave in the same way, will it not? It will not. If you query multiple rows in a single statement then, in almost every other database, READ COMMITTED isolation can be as bad as a dirty read, depending on the implementation. In Oracle, using multi-versioning and read-consistent queries, the answer we get from the ACCOUNTS query is the same in READ COMMITTED as it was in the READ UNCOMMITTED example. Oracle will reconstruct the modified data as it appeared when the query began, returning the answer that was in the database when the query started. Let’s now take a look at how our previous example might work in READ COMMITTED mode in other databases—you might find the answer surprising. We’ll pick up our example at the point described in the previous table: • We are in the middle of the table. We have read and summed the first N rows. • The other transaction has moved $400.00 from account 123 to account 987. • The transaction has not yet committed, so rows containing the information for accounts 123 and 987 are locked. We know what happens in Oracle when it gets to account 987—it will read around the modified data, find out it should be $100.00, and complete. Table 7-4 shows how another database, running in some default READ COMMITTED mode, might arrive at the answer. Table 7-4. Timeline in a Non-Oracle Database Using READ COMMITTED Isolation Time Query Account Transfer Transaction T1 Reads row 1. Sum = $500.00 so far. T2 Reads row 2. Sum = $740.25 so far. T3 Updates row 1 and puts an exclusive lock on row 1, preventing other updates and reads. Row 1 now has $100.00. T4 Reads row N. Sum = . . . T5 Updates row 342,023 and puts an exclusive lock on this row. Row 342,023 now has $500.00. T6 Tries to read row 342,023 and discovers that it is locked. This session will block and wait for this block to become available. All processing on this query stops. T7 Commits transaction. T8 Reads row 342,023, sees $500.00, and presents a final answer that includes the $400.00 double-counted. The first thing to notice is that this other database, upon getting to account 987, will block our query. This session must wait on that row until the transaction holding the exclusive lock

236<br />

CHAPTER 7 ■ CONCURRENCY AND MULTI-VERSIONING<br />

However, achieving READ COMMITTED isolation is not as cut-<strong>and</strong>-dried as it sounds. If you<br />

look at Table 7-1, it appears straightforward. Obviously, given the earlier rules, a query executed<br />

in any database using the READ COMMITTED isolation will behave in the same way, will<br />

it not? It will not. If you query multiple rows in a single statement then, in almost every<br />

other database, READ COMMITTED isolation can be as bad as a dirty read, depending on the<br />

implementation.<br />

In <strong>Oracle</strong>, using multi-versioning <strong>and</strong> read-consistent queries, the answer we get from<br />

the ACCOUNTS query is the same in READ COMMITTED as it was in the READ UNCOMMITTED example.<br />

<strong>Oracle</strong> will reconstruct the modified data as it appeared when the query began, returning the<br />

answer that was in the database when the query started.<br />

Let’s now take a look at how our previous example might work in READ COMMITTED mode in<br />

other databases—you might find the answer surprising. We’ll pick up our example at the point<br />

described in the previous table:<br />

• We are in the middle of the table. We have read <strong>and</strong> summed the first N rows.<br />

• The other transaction has moved $400.00 from account 123 to account 987.<br />

• The transaction has not yet committed, so rows containing the information for<br />

accounts 123 <strong>and</strong> 987 are locked.<br />

We know what happens in <strong>Oracle</strong> when it gets to account 987—it will read around the<br />

modified data, find out it should be $100.00, <strong>and</strong> complete. Table 7-4 shows how another database,<br />

running in some default READ COMMITTED mode, might arrive at the answer.<br />

Table 7-4. Timeline in a Non-<strong>Oracle</strong> <strong>Database</strong> Using READ COMMITTED Isolation<br />

Time Query Account Transfer Transaction<br />

T1 Reads row 1. Sum = $500.00 so far.<br />

T2 Reads row 2. Sum = $740.25 so far.<br />

T3<br />

Updates row 1 <strong>and</strong> puts an exclusive lock<br />

on row 1, preventing other updates <strong>and</strong><br />

reads. Row 1 now has $100.00.<br />

T4 Reads row N. Sum = . . .<br />

T5<br />

Updates row 342,023 <strong>and</strong> puts an exclusive<br />

lock on this row. Row 342,023 now<br />

has $500.00.<br />

T6 Tries to read row 342,023 <strong>and</strong> discovers<br />

that it is locked. This session will block<br />

<strong>and</strong> wait for this block to become<br />

available. All processing on this<br />

query stops.<br />

T7<br />

Commits transaction.<br />

T8 Reads row 342,023, sees $500.00, <strong>and</strong><br />

presents a final answer that includes<br />

the $400.00 double-counted.<br />

The first thing to notice is that this other database, upon getting to account 987, will block<br />

our query. This session must wait on that row until the transaction holding the exclusive lock

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

Saved successfully!

Ooh no, something went wrong!