680

Can someone explain the implications of using with (nolock) on queries, when you should/shouldn't use it?

For example, if you have a banking application with high transaction rates and a lot of data in certain tables, in what types of queries would nolock be okay? Are there cases when you should always use it/never use it?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Andy White
  • 86,444
  • 48
  • 176
  • 211
  • I subquestioned in http://stackoverflow.com/questions/3836282/what-are-locking-issues-in-olap and http://stackoverflow.com/questions/3836032/what-are-locking-deadlocking-issues-in-financial-operations mostly Jonathan Allen's answer http://stackoverflow.com/questions/686724/sql-when-should-you-use-with-nolock/686941#686941 – Gennady Vanin Геннадий Ванин Oct 01 '10 at 06:31
  • 1
    one link here - http://www.mssqltips.com/sqlservertip/2470/understanding-the-sql-server-nolock-hint/ – Steam Oct 29 '13 at 20:33
  • 1
    Here is an excellent summary of the implications of using NOLOCK http://blogs.msdn.com/b/davidlean/archive/2009/04/06/sql-server-nolock-hint-other-poor-ideas.aspx – Bryan Jul 13 '15 at 22:04

16 Answers16

525

WITH (NOLOCK) is the equivalent of using READ UNCOMMITED as a transaction isolation level. So, you stand the risk of reading an uncommitted row that is subsequently rolled back, i.e. data that never made it into the database. So, while it can prevent reads being deadlocked by other operations, it comes with a risk. In a banking application with high transaction rates, it's probably not going to be the right solution to whatever problem you're trying to solve with it IMHO.

David M
  • 71,481
  • 13
  • 158
  • 186
  • 176
    Most banking applications can safely use nolock because they are transactional in the business sense. You only write new rows, you never update them. – Jonathan Allen Mar 26 '09 at 17:56
  • 55
    @Grauenwolf- An inserted but uncommitted row could still lead to dirty reads. – saasman Mar 26 '09 at 21:03
  • 19
    @Saasman- If you don't ever rollback transactions, that doesn't matter. And with a insert-only table, the chances of a rollback are slim to none. And if they do occur, you will still fix it all in the end of day variance report. – Jonathan Allen Mar 27 '09 at 18:47
  • If the inserted records contain information (attributes) which are coming from another transaction table which is also heavy on traffic, then this will not be a good idea. If the source table record is rolled back, then the data just inserted to the latter table will be invalid – Faiz Oct 21 '12 at 06:09
  • 2
    I am entrenched. I assume the Added no lock hints on. For Examp: – Ross Bush Sep 11 '13 at 02:17
  • 13
    If you use `NOLOCK` with a `SELECT` you run the risk of returning the same rows more than once (duplicated data) if data is ever inserted (or updated) into the table while doing a select. – Ian Boyd Sep 19 '13 at 00:31
  • Again, having a wrong value isn't necessarily the end of the world. While I am certainly against randomly sprinkling nolock on every query, I'm not going to worry about a missing row in a query that shows the day's sales totals rounded to the nearest thousand. – Jonathan Allen Jul 25 '14 at 19:04
  • 6
    This is old be worth explicitly saying: NOLOCK should not be used if you require accurate, repeatable, query results. Period. The lead assertion that they can be safely used in a banking application is simply inaccurate. If you can tolerate some loss of fidelity, only then is it's use appropriate. – Graham Oct 10 '19 at 14:47
  • 1
    Some financial institutions are using NoSQL databases like MongoDB. Such databases often perform all queries with what we call NOLOCK and don't have any alternative modes. Irregardless of your opinion as to its appropriateness, it happens, a lot. – Jonathan Allen Nov 23 '22 at 23:03
185

The question is what is worse:

  • a deadlock, or
  • a wrong value?

For financial databases, deadlocks are far worse than wrong values. I know that sounds backwards, but hear me out. The traditional example of DB transactions is you update two rows, subtracting from one and adding to another. That is wrong.

In a financial database you use business transactions. That means adding one row to each account. It is of utmost importance that these transactions complete and the rows are successfully written.

Getting the account balance temporarily wrong isn't a big deal, that is what the end of day reconciliation is for. And an overdraft from an account is far more likely to occur because two ATMs are being used at once than because of a uncommitted read from a database.

That said, SQL Server 2005 fixed most of the bugs that made NOLOCK necessary. So unless you are using SQL Server 2000 or earlier, you shouldn't need it.

Further Reading
Row-Level Versioning

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • 23
    Getting an account balance temporarily wrong is not a big deal? What if that transaction is the one where you are taking out cash from an atm without any overdraft limit? – Learning Mar 26 '09 at 18:15
  • 13
    @Learning: What happens if you take out the money 30 seconds before someone charges your card? Until all communication is turly instaneous, overdrafts will be a fact of life. – Jonathan Allen Mar 27 '09 at 18:44
  • 7
    +1 In financial app (everywhere, no only in banks), there are neither updates nor deletes. Even incorrect operations are corrected by inserting records. What is this term in English? Is it "storno"? Google did not help me to answer this question – Gennady Vanin Геннадий Ванин Oct 01 '10 at 01:23
  • 8
    Late entry... deadlocks should be caught and retried. Dirty reads have consequences – gbn Sep 29 '11 at 19:20
  • 4
    @JonathanAllen just an fyi, the term is UTmost, not UP. – Jimmy D Aug 20 '13 at 18:10
  • Do retail banks use SQL server for call account records? – NeedHack Oct 10 '14 at 08:54
  • I've never worked at a retail bank, but I did work for a company that handled bond trading and they used SQL Server for everything. – Jonathan Allen Oct 11 '14 at 23:00
  • A bank that would return the wrong balance to me wouldn't see my money any more. Easy as that. It's better to have timeouts than the wrong amount in the account. – darlove Nov 04 '16 at 09:41
  • 3
    Banks often show the wrong balance. Depending on the merchant system and the day of the week, it can take several days for a purchase to actually be logged against your account. – Jonathan Allen Nov 08 '16 at 16:47
  • Getting a balance temporarily wrong can lead to [fines running into the millions](http://www.lexology.com/library/detail.aspx?g=3552af81-6715-4e74-bcd4-f964fe442abd). [FinCEN](https://www.fincen.gov/) gets pretty grumpy if a [customer did $10,000 worth of transactions](https://www.fincen.gov/sites/default/files/shared/CTRPamphletBW.pdf) and you don't report it. Be careful intentionally using incorrect data with in the financial world. People get very grumpy when it comes to financial stuffs. – Ian Boyd Feb 14 '17 at 15:07
  • 2
    Until all communication is instantaneous, balances are going to be temporarily wrong from time to time. Fortunately the kind of report you're talking about wouldn't be run until the transactions have gone through the reconciliation process so we're no longer talking about volatile data that would benefit from a nolock. It probably won't even be on the main database, but rather a special reporting database that is updated daily. – Jonathan Allen Feb 14 '17 at 19:26
  • 2
    @IanBoyd the fine you link to was ["for willful and egregious violations of the Bank Secrecy Act,"](https://www.fincen.gov/news/news-releases/fincen-fines-tinian-dynasty-hotel-casino-75-million-egregious-anti-money) not for getting a balance temporarily wrong. – phoog May 15 '18 at 18:31
  • @phoog Government auditors get quite grumpy when you didn't do a report on a customer that you should have. End of the day reconciliation doesn't help when the customer is no longer here, and we can't ask them for their name, address, phone number, occupation, name of employer, work phone, country of citizenship, and look at their ID. You get the information at the time, or you get fined. Personally, i would love to tell government auditors to go do something anatomically impossible to themselves - but i'm not allowed to talk to them anymore after the last time i made my displeasure known. – Ian Boyd May 16 '18 at 14:31
  • @NeedHack Yes, some banks use SQL Server. My roommate wrote software for credit unions. Originally they used a custom mainframe database, basically 80's era NoSQL. Now they offer the option of either SQL Server or a custom relational database written in Java. – Jonathan Allen Mar 24 '22 at 03:02
65

Unfortunately it's not just about reading uncommitted data. In the background you may end up reading pages twice (in the case of a page split), or you may miss the pages altogether. So your results may be grossly skewed.

Check out Itzik Ben-Gan's article. Here's an excerpt:

" With the NOLOCK hint (or setting the isolation level of the session to READ UNCOMMITTED) you tell SQL Server that you don't expect consistency, so there are no guarantees. Bear in mind though that "inconsistent data" does not only mean that you might see uncommitted changes that were later rolled back, or data changes in an intermediate state of the transaction. It also means that in a simple query that scans all table/index data SQL Server may lose the scan position, or you might end up getting the same row twice. "

Tobias J
  • 19,813
  • 8
  • 81
  • 66
sqlbelle
  • 696
  • 6
  • 3
  • 8
    A bit further down he explains how to get the same row twice: **I’ll recreate the table T1 such that the clustered index on col1 will be defined as a unique index with the option IGNORE_DUP_KEY. This means that duplicate values cannot exist in col1, and also that an attempt to insert a duplicate key will not fail the transaction and generate an error rather just generate a warning.** If you don't use this weird option you probably don't have to worry about getting rows twice – HH321 Mar 10 '12 at 13:00
  • 1
    You can still get dupe rows even without the wired option - if your query leverages an index that is not unique, for instance. This isn't unique to nolock, though. – RMD Nov 08 '13 at 05:10
57

The text book example for legitimate usage of the nolock hint is report sampling against a high update OLTP database.

To take a topical example. If a large US high street bank wanted to run an hourly report looking for the first signs of a city level run on the bank, a nolock query could scan transaction tables summing cash deposits and cash withdrawals per city. For such a report the tiny percentage of error caused by rolled back update transactions would not reduce the value of the report.

saasman
  • 611
  • 4
  • 4
33

Not sure why you are not wrapping financial transactions in database transactions (as when you transfer funds from one account to another - you don't commit one side of the transaction at-a-time - this is why explicit transactions exist). Even if your code is braindead to business transactions as it sounds like it is, all transactional databases have the potential to do implicit rollbacks in the event of errors or failure. I think this discussion is way over your head.

If you are having locking problems, implement versioning and clean up your code.

No lock not only returns wrong values it returns phantom records and duplicates.

It is a common misconception that it always makes queries run faster. If there are no write locks on a table, it does not make any difference. If there are locks on the table, it may make the query faster, but there is a reason locks were invented in the first place.

In fairness, here are two special scenarios where a nolock hint may provide utility

1) Pre-2005 sql server database that needs to run long query against live OLTP database this may be the only way

2) Poorly written application that locks records and returns control to the UI and readers are indefinitely blocked. Nolock can be helpful here if application cannot be fixed (third party etc) and database is either pre-2005 or versioning cannot be turned on.

user229044
  • 232,980
  • 40
  • 330
  • 338
Andrew
  • 419
  • 4
  • 2
  • 13
    I agree with you that NOLOCK shouldn't be used to make up for poorly written code. However, I think your attack of Johnathan is unwarranted since he never actually mentioned _database_ transactions. He was simply pointing out that financial applications typically do not allow edits to records (obviously there are some exceptions). In your fund transfer example, he's saying it would be strange if you were to _mutate_ the value of the account's balance instead of _adding_ a debit/credit entry to a ledger of sorts. – chrnola Apr 22 '14 at 15:06
  • 24
    When funds are transfered from one account to another at different banks what do you think happens? Some uber-database takes a lock on a table at Bank of America and another at Wells Fargo? No. A financial transaction is written to each and then an end-of-day process verifes that all of the records match up. – Jonathan Allen Jul 25 '14 at 18:58
24

You can use it when you're only reading data, and you don't really care about whether or not you might be getting back data that is not committed yet.

It can be faster on a read operation, but I cannot really say by how much.

In general, I recommend against using it - reading uncommitted data can be a bit confusing at best.

TylerH
  • 20,799
  • 66
  • 75
  • 101
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    it would be nice if you mentioned the fact that SQL Server 2005 has row versioning so nolocks aren't even needed any more. – Jonathan Allen Mar 26 '09 at 18:09
  • Well, the "with (nolock)" still has its place even in SQL Server 2005 - but the benefits are getting slimmer and slimmer, that's true. – marc_s Mar 26 '09 at 20:38
24

NOLOCK is equivalent to READ UNCOMMITTED, however Microsoft says you should not use it for UPDATE or DELETE statements:

For UPDATE or DELETE statements: This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.

http://msdn.microsoft.com/en-us/library/ms187373.aspx

This article applies to SQL Server 2005, so the support for NOLOCK exists if you are using that version. In order to future-proof you code (assuming you've decided to use dirty reads) you could use this in your stored procedures:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Seibar
  • 68,705
  • 38
  • 88
  • 99
18

Another case where it's usually okay is in a reporting database, where data is perhaps already aged and writes just don't happen. In this case, though, the option should be set at the database or table level by the administrator by changing the default isolation level.

In the general case: you can use it when you are very sure that it's okay to read old data. The important thing to remember is that its very easy to get that wrong. For example, even if it's okay at the time you write the query, are you sure something won't change in the database in the future to make these updates more important?

I'll also 2nd the notion that it's probably not a good idea in banking app. Or inventory app. Or anywhere you're thinking about transactions.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 4
    As a person who works on banking applications, I have to say no-locks are not a problem. Transactional records, that is rows that are inserted but never updated or deleted, are surprising resistant to the problems of reading uncommited data. – Jonathan Allen Mar 26 '09 at 18:02
17

Short answer:

Only use WITH (NOLOCK) in SELECT statement on tables that have a clustered index.

Long answer:

WITH(NOLOCK) is often exploited as a magic way to speed up database reads.

The result set can contain rows that have not yet been committed, that are often later rolled back.

If WITH(NOLOCK) is applied to a table that has a non-clustered index then row-indexes can be changed by other transactions as the row data is being streamed into the result-table. This means that the result-set can be missing rows or display the same row multiple times.

READ COMMITTED adds an additional issue where data is corrupted within a single column where multiple users change the same cell simultaneously.

WonderWorker
  • 8,539
  • 4
  • 63
  • 74
  • 2
    Reading uncommitted data is acceptable if it doesn't change the final decision. For example, if you are trying to project how much money your retail store is going to make over the next 6 months, seeing that Tammy bought 2 rolls of paper towels when she really bought 3 isn't going to change your opinion of the future. – Jonathan Allen Aug 02 '16 at 09:57
  • 1
    If your filter includes now, your data is going to be inaccurate the moment you run the query. If your filter only includes historical data, using `READ UNCOMITTED` won't affect it at all. There is a reason why it was included in the ANSI standard. – Jonathan Allen Aug 02 '16 at 23:18
  • 3
    Never say never. If you NEED the data to be 100% accurate, then you shouldn't use nolock. For me, this usually isn't the case. When presenting data to a user, by the time they act on the data, it may have already changed anyway, but most likely did not, and the lock contention isn't worth the response delays. – Perposterer Feb 26 '18 at 15:44
  • Let's stick to systems worthy of existence. Don't forget that Tammy has a perfectly decent brain, so to use a database to record tiny paper towel purchases that nobody takes any notice of is preposterous at best. Our focus are systems that are actually important e.g. getting people paid on time, responding to emergencies, etc. It is of significant benefit that the use of WITH(NOLOCK) is understood by the people programming any system worthy of existence. When a person can do a better job than a database then consider repurposing those resources. – WonderWorker Feb 24 '20 at 15:29
15

Simple answer - whenever your SQL is not altering data, and you have a query that might interfere with other activity (via locking).

It's worth considering for any queries used for reports, especially if the query takes more than, say, 1 second.

It's especially useful if you have OLAP-type reports you're running against an OLTP database.

The first question to ask, though, is "why am I worrying about this?" ln my experience, fudging the default locking behavior often takes place when someone is in "try anything" mode and this is one case where unexpected consequences are not unlikely. Too often it's a case of premature optimization and can too easily get left embedded in an application "just in case." It's important to understand why you're doing it, what problem it solves, and whether you actually have the problem.

dkretz
  • 37,399
  • 13
  • 80
  • 138
12

My 2 cents - it makes sense to use WITH (NOLOCK) when you need to generate reports. At this point, the data wouldn't change much & you wouldn't want to lock those records.

SoftwareGeek
  • 15,234
  • 19
  • 61
  • 78
9

If you are handling finance transactions then you will never want to use nolock. nolock is best used to select from large tables that have lots updates and you don't care if the record you get could possibly be out of date.

For financial records (and almost all other records in most applications) nolock would wreak havoc as you could potentially read data back from a record that was being written to and not get the correct data.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • 5
    Surprisingly, when working with financial data this isn't an issue. Since rows are never edited and accounts are reconciled at the end of the day, reading temporarily bogus data doesn't do anything. – Jonathan Allen Mar 26 '09 at 18:00
  • Could you please share the source for your answer? – Shad Jun 15 '22 at 12:35
8

I've used to retrieve a "next batch" for things to do. It doesn't matter in this case which exact item, and I have a lot of users running this same query.

Otávio Décio
  • 73,752
  • 17
  • 161
  • 228
  • 1
    We do something similar to present a background task with a queue of work to do. If, when it gets to a particular record it no longer exists/matches the selection criteria, it just moves on to the next. – TripeHound Apr 25 '14 at 08:26
7

Use nolock when you are okay with the "dirty" data. Which means nolock can also read data which is in the process of being modified and/or uncommitted data.

It's generally not a good idea to use it in high transaction environment and that is why it is not a default option on query.

Learning
  • 8,029
  • 3
  • 35
  • 46
  • 4
    The only time you need it is in a high transaction environment. If your tables are mostly idle, then you wouldn't gain anything by it. – Jonathan Allen Mar 26 '09 at 18:13
7

I use with (nolock) hint particularly in SQLServer 2000 databases with high activity. I am not certain that it is needed in SQL Server 2005 however. I recently added that hint in a SQL Server 2000 at the request of the client's DBA, because he was noticing a lot of SPID record locks.

All I can say is that using the hint has NOT hurt us and appears to have made the locking problem solve itself. The DBA at that particular client basically insisted that we use the hint.

By the way, the databases I deal with are back-ends to enterprise medical claims systems, so we are talking about millions of records and 20+ tables in many joins. I typically add a WITH (nolock) hint for each table in the join (unless it is a derived table, in which case you can't use that particular hint)

user52212
  • 603
  • 3
  • 8
  • 18
  • 1
    SQL Server 2005 added "row versioning" which should greatly reduce the need for nolocks. We recently upgraded and are not in training our DBAs to stop using them. – Jonathan Allen Mar 26 '09 at 18:11
5

The simplest answer is a simple question - do you need your results to be repeatable? If yes then NOLOCKS is not appropriate under any circumstances

If you don't need repeatability then nolocks may be useful, especially if you don't have control over all processes connecting to the target database.

Ed Green
  • 128
  • 1
  • 2