![]() |
|
|
By: Greg Robidoux | Read Comments (4) | Print Greg is the President of Edgewood Solutions and a co-founder of MSSQLTips.com. Related Tips: 1 | 2 | 3 | 4 | 5 | 6 | 7 | More |
|
I see the use of the NOLOCK hint in existing code for my stored procedures and I am not exactly sure if this is helpful or not. It seems like this has been a practice that was put in place and now is throughout all of the code wherever there are SELECT statements. Can you explain the what NOLOCK does and whether this is a good practice or not?
It seems that in some SQL Server shops the use of the NOLOCK (aka READUNCOMMITED) hint is used throughout the application. In this tip we take a closer look at how this works and what the issues maybe when using NOLOCK.
Let's walk through some simple examples to see how this works. (These queries are run against the AdventureWorks database.)
Here is a query that returns all of the data from the Person.Contact table. If I run this query I can see there is only one record that has a Suffix value for ContactID = 12.

Let's say another user runs the below query in a transaction. The query completes and updates the records, but it is not yet committed to the database so the records are locked.
-- run in query window 1 BEGIN TRAN UPDATE Person.Contact SET Suffix = 'B' WHERE ContactID < 20 -- ROLLBACK or COMMIT
If I run the same query from above again you will notice that it never completes, because the UPDATE has not yet been committed.
If I run sp_who2 I can see that the SELECT statement is being blocked. I will need to either cancel this query or COMMIT or ROLLBACK the query in window one for this to complete. For this example I am going to cancel the SELECT query.

To get around the locked records, I can use the NOLOCK hint as shown below and the query will complete even though the query in window 1 is still running and has not been committed or rolled back.
If you notice below the Suffix column now has "B" for all records. This is because the UPDATE in window 1 updated these records. Even though that transaction has not been committed, since we are using the NOLOCK hint SQL Server ignores the locks and returns the data. If the UPDATE is rolled back the data will revert back to what it looked like before, so this is considered a Dirty Read because this data may or may not exist depending on the final outcome in query window 1.

If I rollback the UPDATE using the ROLLBACK command and rerun the SELECT query we can see the Suffix is back to what it looked like before.

So the issue with using the NOLOCK hint is that there is the possibility of reading data that has been changed, but not yet committed to the database. If you are running reports and do not care if the data might be off then this is not an issue, but if you are creating transactions where the data needs to be in a consistent state you can see how the NOLOCK hint could return false data.
So what kind of locking is used when the NOLOCK hint is used.
If we run our SELECT without NOLOCK we can see the locks that are taken if we use sp_lock. (To get the lock information I ran sp_lock in another query window while this was running.)

If we do the same for our SELECT with the NOLOCK we can see these locks.

The differences are that there is a "S" shared access lock that is put on the page (PAG) that we are reading for the first 19 rows of data in the table when we don't use NOLOCK. Also, we are getting a Sch-S lock versus an IS lock for the table (TAB).
So another thing to point out is that even when you just SELECT data SQL Server still creates a lock to make sure the data is consistent.
These are the lock types and the lock modes that are used for the above two queries.
The NOLOCK hint is the same as the READUNCOMMITED hint and can be used as follows with the same results.
The NOLOCK and READUNCOMMITED hints are only allowed with SELECT statements. If we try to use this for an UPDATE, DELETE or INSERT we will get an error.
Since a NOLOCK hint needs to get a Sch-S (schema stability) lock, a SELECT using NOLOCK could still be blocked if a table is being altered and not committed. Here is an example.
If we try to run our SELECT statement it will be blocked until the above is committed or rolled back.
We mentioned above how you can get dirty reads using the NOLOCK hint. These are also other terms you may encounter for this hint.
To learn more about these issues read this article: http://msdn.microsoft.com/en-us/library/ms190805.aspx
You can also set the Isolation Level for all queries instead of using the NOLOCK or READUNCOMMITTED hint. The isolation level will apply the READUNCOMMITTED to all SELECT statements that are performed from when this is turned on until it is turned off.
In the example below, the two SELECT statements will use the READUNCOMMITED or NOLOCK hint and the UPDATE will still function as normal. This way you can set a whole batch of statements instead of modifying each query.
| Share: | Share | Tweet |
|
![]() |
![]() |
Free SQL Server Learning |
| Tuesday, August 16, 2011 - 10:07:21 AM - TheSmilingDBA | Read The Tip |
|
Great explanation. Thanks Greg. I believe NOLOCK is going to be deprecated in a future version of SQL, so users might want to use READUNCOMMEITTED and not NOLOCK. Itzik Ben-Gan has shown a case where a page split causes a double read of some data using NOLOCKs. You might wnat to BING it!!! Thomas
|
|
| Tuesday, August 16, 2011 - 11:21:56 AM - Mike | Read The Tip |
|
Thanks Greg, for this explanation. But I miss something. A select that is send to the Database can also create a LOCK-Situation if you don't use the NOLOCK statement. So not only updatestatement's can create Locks. If you use an select statement on an bigger table with 'order' or 'group by' statements in it, you will quick notice that there are some performence Problem's on your Database. Maybe your statement will escalate the lock to an Table-Lock. Nice overviews of Locking you will get with http://www.sommarskog.se/sqlutil/aba_lockinfo.html greetings from Germany Mike |
|
| Tuesday, August 16, 2011 - 11:38:41 AM - Greg Robidoux | Read The Tip |
|
Hi Mike, yes your correct. A SELECT still places a shared lock on the data. I tried to show an example of this under the LOCKS section of the tip. Since I am only doing a small set of records a PAGE lock was used, but this could get escalated to a TABLE lock as you mentioned. |
|
| Wednesday, August 17, 2011 - 7:52:44 AM - Scott C | Read The Tip |
|
At a previous job we had a web developer that thought GUID primary keys were a great idea. (Could be one of the reasons he later got canned.) We found that SELECT COUNT(*) FROM <table with GUID PK> WITH (NOLOCK) was not accurate, even when there was no other activity in the table. Repeatedly running the command would produce answers that varied up or down by a small amount, apparently at random. This was in SQL 2005, don't know if it is fixed in 2008. Other than that, it is very useful for running reports on a production database without killing all the apps. Not very good for accurately updating bank balances. |
|
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |