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 One of the key challenges in developing multiuser, database-driven applications is to maximize concurrent access and, at the same time, ensure that each user is able to read and modify the data in a consistent fashion. The locking mechanisms that allow this to happen are key features of any database, and Oracle excels in providing them. However, Oracle’s implementation of these features is specific to Oracle—just as SQL Server’s implementation is to SQL Server—and it is up to you, the application developer, to ensure that when your application performs data manipulation, it uses these mechanisms correctly. If you fail to do so, your application will behave in an unexpected way, and inevitably the integrity of your data will be compromised (as was demonstrated in Chapter 1). In this chapter, we’ll take a detailed look at how Oracle locks both data (e.g., rows in tables) and shared data structures (such as those found in the SGA). We’ll investigate the granularity to which Oracle locks data and what that means to you, the developer. When appropriate, I’ll contrast Oracle’s locking scheme with other popular implementations, mostly to dispel the myth that row-level locking adds overhead; it adds overhead only if the implementation adds overhead. In the next chapter, we’ll continue this discussion and investigate Oracle’s multiversioning techniques and how locking strategies interact with them. What Are Locks? Locks are mechanisms used to regulate concurrent access to a shared resource. Note how I used the term “shared resource” and not “database row.” It is true that Oracle locks table data at the row level, but it also uses locks at many other levels to provide concurrent access to various resources. For example, while a stored procedure is executing, the procedure itself is locked in a mode that allows others to execute it, but it will not permit another user to alter it in any way. Locks are used in the database to permit concurrent access to these shared resources, while at the same time providing data integrity and consistency. In a single-user database, locks are not necessary. There is, by definition, only one user modifying the information. However, when multiple users are accessing and modifying data or data structures, it is crucial to have a mechanism in place to prevent concurrent modification of the same piece of information. This is what locking is all about. It is very important to understand that there are as many ways to implement locking in a database as there are databases. Just because you have experience with the locking model of one particular relational database management system (RDBMS) does not mean you know everything about locking. For example, before I got heavily involved with Oracle, I used other databases such as Sybase, Microsoft SQL Server, and Informix. All three of these databases 183

184 CHAPTER 6 ■ LOCKING AND LATCHING provide locking mechanisms for concurrency control, but there are deep and fundamental differences in the way locking is implemented in each one. To demonstrate this, I’ll outline my progression from a SQL Server developer to an Informix user and finally an Oracle developer. This happened many years ago, and the SQL Server fans out there will tell me “But we have row-level locking now!” It is true: SQL Server may now use row-level locking, but the way it is implemented is totally different from the way it is done in Oracle. It is a comparison between apples and oranges, and that is the key point. As a SQL Server programmer, I would hardly ever consider the possibility of multiple users inserting data into a table concurrently. It was something that just didn’t often happen in that database. At that time, SQL Server provided only for page-level locking and, since all the data tended to be inserted into the last page of nonclustered tables, concurrent inserts by two users was simply not going to happen. ■Note A SQL Server clustered table (a table that has a clustered index) is in some regard similar to, but very different from, an Oracle cluster. SQL Server used to only support page (block) level locking, and if every row inserted was to go to the “end” of the table, you would never have had concurrent inserts, concurrent transactions in that database. The clustered index in SQL Server was used to cause rows to be inserted all over the table, in sorted order by the cluster key, and as such was used to improve concurrency in that database. Exactly the same issue affected concurrent updates (since an UPDATE was really a DELETE followed by an INSERT). Perhaps this is why SQL Server, by default, commits or rolls back immediately after execution of each and every statement, compromising transactional integrity in an attempt to gain higher concurrency. So in most cases, with page-level locking, multiple users could not simultaneously modify the same table. Compounding this was the fact that while a table modification was in progress, many queries were also effectively blocked against that table. If I tried to query a table and needed a page that was locked by an update, I waited (and waited and waited). The locking mechanism was so poor that providing support for transactions that took more than a second was deadly—the entire database would appear to “freeze” if you did. I learned a lot of bad habits here. I learned that transactions were “bad” and that you ought to commit rapidly and never hold locks on data. Concurrency came at the expense of consistency. You either wanted to get it right or get it fast. I came to believe that you couldn’t have both. When I moved on to Informix, things were better, but not by much. As long as I remembered to create a table with row-level locking enabled, then I could actually have two people simultaneously insert data into that table. Unfortunately, this concurrency came at a high price. Row-level locks in the Informix implementation were expensive, both in terms of time and memory. It took time to acquire and “unacquire” or release them, and each lock consumed real memory. Also, the total number of locks available to the system had to be computed prior to starting the database. If you exceeded that number, then you were just out of luck. Consequently, most tables were created with page-level locking anyway, and, as with SQL Server, both row and page-level locks would stop a query in its tracks. As a result, I found that once again I would want to commit as fast as I could. The bad habits I picked up using SQL Server

184<br />

CHAPTER 6 ■ LOCKING AND LATCHING<br />

provide locking mechanisms for concurrency control, but there are deep <strong>and</strong> fundamental<br />

differences in the way locking is implemented in each one. To demonstrate this, I’ll outline my<br />

progression from a SQL Server developer to an Informix user <strong>and</strong> finally an <strong>Oracle</strong> developer.<br />

This happened many years ago, <strong>and</strong> the SQL Server fans out there will tell me “But we have<br />

row-level locking now!” It is true: SQL Server may now use row-level locking, but the way it is<br />

implemented is totally different from the way it is done in <strong>Oracle</strong>. It is a comparison between<br />

apples <strong>and</strong> oranges, <strong>and</strong> that is the key point.<br />

As a SQL Server programmer, I would hardly ever consider the possibility of multiple<br />

users inserting data into a table concurrently. It was something that just didn’t often happen<br />

in that database. At that time, SQL Server provided only for page-level locking <strong>and</strong>, since all<br />

the data tended to be inserted into the last page of nonclustered tables, concurrent inserts by<br />

two users was simply not going to happen.<br />

■Note A SQL Server clustered table (a table that has a clustered index) is in some regard similar to, but<br />

very different from, an <strong>Oracle</strong> cluster. SQL Server used to only support page (block) level locking, <strong>and</strong> if every<br />

row inserted was to go to the “end” of the table, you would never have had concurrent inserts, concurrent<br />

transactions in that database. The clustered index in SQL Server was used to cause rows to be inserted<br />

all over the table, in sorted order by the cluster key, <strong>and</strong> as such was used to improve concurrency in that<br />

database.<br />

Exactly the same issue affected concurrent updates (since an UPDATE was really a DELETE<br />

followed by an INSERT). Perhaps this is why SQL Server, by default, commits or rolls back<br />

immediately after execution of each <strong>and</strong> every statement, compromising transactional<br />

integrity in an attempt to gain higher concurrency.<br />

So in most cases, with page-level locking, multiple users could not simultaneously<br />

modify the same table. Compounding this was the fact that while a table modification was in<br />

progress, many queries were also effectively blocked against that table. If I tried to query a<br />

table <strong>and</strong> needed a page that was locked by an update, I waited (<strong>and</strong> waited <strong>and</strong> waited). The<br />

locking mechanism was so poor that providing support for transactions that took more than a<br />

second was deadly—the entire database would appear to “freeze” if you did. I learned a lot of<br />

bad habits here. I learned that transactions were “bad” <strong>and</strong> that you ought to commit rapidly<br />

<strong>and</strong> never hold locks on data. Concurrency came at the expense of consistency. You either<br />

wanted to get it right or get it fast. I came to believe that you couldn’t have both.<br />

When I moved on to Informix, things were better, but not by much. As long as I remembered<br />

to create a table with row-level locking enabled, then I could actually have two people<br />

simultaneously insert data into that table. Unfortunately, this concurrency came at a high<br />

price. Row-level locks in the Informix implementation were expensive, both in terms of time<br />

<strong>and</strong> memory. It took time to acquire <strong>and</strong> “unacquire” or release them, <strong>and</strong> each lock consumed<br />

real memory. Also, the total number of locks available to the system had to be computed prior<br />

to starting the database. If you exceeded that number, then you were just out of luck. Consequently,<br />

most tables were created with page-level locking anyway, <strong>and</strong>, as with SQL Server,<br />

both row <strong>and</strong> page-level locks would stop a query in its tracks. As a result, I found that once<br />

again I would want to commit as fast as I could. The bad habits I picked up using SQL Server

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

Saved successfully!

Ooh no, something went wrong!