I have seen many examples of the HOLDLOCK hint being used in combination with UPDLOCK (like this). However Microsoft's documentation for these hints make it seem like HOLDLOCK should be redundant, since UPDLOCK already persists the lock until the end of the transaction. (Also it seems to say that HOLDLOCK only applies to shared locks anyway.)
How does HOLDLOCK affect the query, if at all?
Basically, HOLDLOCK is equivalent to using a Serializable transaction, which locks everything that is affected so that the transaction is guaranteed to be fully ACID-compliant. UPDLOCK makes the locks to be taken and held until the transaction completes.
UPDLOCK places update locks on rows that are being selected until the end of the transaction. Other transaction cannot update or delete the row but they are allowed to select it. ROWLOCK places locks on row level opposed to a page or table lock. READPAST Records that are locked are not returned.
A LCK_M_U is an update lock on a table/index (not on a database), that's quite normal when you update data in a database.
The sp_lock result set contains one row for each lock held by the sessions specified in the @spid1 and @spid2 parameters. If neither @spid1 nor @spid2 is specified, the result set reports the locks for all sessions currently active in the instance of the Database Engine. Column name. Data type. Description.
It has a large impact.
The Update lock takes an Update lock on the row, Intent update on the page and a shared lock on the table / database.
This does not stop other queries from accessing the data within the table, since the locks on the page / database are purely share locks. They just may not clash locks against the individual row / page / table by attempting to perform an operation that would contradict locks. If that occured the request would queue behind the current locks and wait for it to come available before it could proceed.
By using holdlock, the query is being forced to be serialised, locking the table exclusively until the action has completed. This prevents anyone from reading the table unless the nolock hint is used, allowing a potentially dirty read.
To see the effect, generate an example table 'foo' and put some trash data in it.
begin tran select * from foo with (updlock) where tableid = 1 -- notice there is no commit tran
Open another window and try:
select * from foo
The rows come back, now commit the original query transaction. Re-run it altered to use holdlock as well:
begin tran select * from foo with (updlock, holdlock) where tableid = 1
Go back to the other window and try select the data again, the query will not return values since it is blocked by the exclusive lock. Commit the transaction on the first window and the results to the second query will appear since it is no longer blocked.
Final test is to use the nolock, run the transaction again using updlock and holdlock. then run the following in the second window:
select * from foo (nolock)
The results will come back automatically, since you have accepted the risk of a dirty read (read uncommitted).
So it is seen to have a large impact, in that you are forcing actions against that table to be serialised which might be what you want (depending on the update being made) or will create a very large bottleneck on that table. If everyone did that to a busy table with long running transactions then it would cause significant delays within an application.
As with all SQL features, when used correctly they can be powerful, but mis-use of a feature / hint can cause significant problems. I prefer to use hints as a last resort for when I have to override the engine - not as a default approach.
Edit as Requested : Tested in SQL 2005, 2008, 2008R2 (All Enterprise) - all installed on pretty much default settings, test database created using all defaults (just entered the name of the DB only).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With