Ranting about NOLOCK right after my CLR post might be fanning the flames, but I’m actively dealing with these topics so they are fresh on my mind. And we all like a good argument anyway, right?
So at the risk of starting more fights…
NOLOCK is not a performance optimization
It’s a concurrency shortcut that trades correctness for the illusion of speed. Most people using it don’t fully understand what they’re giving up, and I am convinced those people are doing it out of a bad, old habit.
That doesn’t mean everyone who uses NOLOCK is lazy or reckless. It does mean the hint has been copy pasted into too many scripts because “it avoids blocking” and “everyone does it.”
Why NOLOCK Is So Tempting
I get why NOLOCK exists in so many environments.
(I also get that I used WAY too many bullets in this blog post, and I am very sorry. Every time I reread it, I tried to remove a few more. I blame the fact that I wrote this from a white paper that I wrote that was designed to make the topic understandable to nontechnical folks.)
You have:
- High-volume inserts or updates
- Reports timing out
- Blocking chains that look scary in Activity Monitor
Someone adds WITH (NOLOCK) and suddenly:
- The report runs
- The blocking graph quiets down
- Everyone breathes again
It looks like an easy win.
The problem is that NOLOCK doesn’t fix blocking. It just tells SQL Server to stop caring whether the data makes sense. If that doesn’t scare you, I don’t know what would.
What NOLOCK Actually Means
NOLOCK is functionally equivalent to READ UNCOMMITTED. You are explicitly telling SQL Server:
- “I’m okay reading data that isn’t committed”
- “I’m okay reading data that may never actually exist”
- “I’m okay if rows disappear or show up twice”
- “I’m okay if my data is bad.”
When I put it that way, I hope even more that you hate the idea of this hint.
Dirty Reads Are the Least Dangerous Part
Dirty reads are the example everyone uses and ironically, they’re not even the worst problem.
Example Scenario:
- A process updates 10,000 rows
- A report runs with NOLOCK
- The process errors and rolls back
Your report just included data that never existed.
What’s worse is what happens during allocation scans.
Missing Rows and Double Counting
When SQL Server scans data, it relies on allocation structures to find where rows live. With NOLOCK, SQL Server is allowed to read these structures while they are actively changing.
If a page split or row movement happens mid-scan, SQL Server can:
- Skip rows entirely
- Read the same rows twice
This isn’t theoretical physics. Microsoft documents this behavior explicitly.
- Counts can be wrong
- Aggregates can be wrong
- Financial reports can be wrong
Why People Don’t Notice
NOLOCK failures are subtle and obnoxious.
They don’t:
- Crash queries
- Throw exceptions
- Leave obvious forensic evidence
They show up as:
- “Why does this report not match that one?”
- “Why are yesterday’s numbers different today when nothing changed?”
- “It only happens occasionally.”
The Thing People Actually Want: RCSI
In almost every situation with NOLOCK, what people really want is this:
“Readers shouldn’t block writers, and writers shouldn’t block readers.”
Good news! SQL Server already solved that!
Read Committed Snapshot Isolation (RCSI) gives you:
- Non-blocking reads
- Guaranteed committed data
- Zero query-level hints
- No application code changes
Readers see the last committed version of a row via TempDB row versioning. Writers keep doing their thing. Everyone gets what they want correctly.
There are some things to consider with RCSI though!
Yes, there’s TempDB overhead.
Yes, you should size and monitor it.
Yes, large transactions should still consider batching for better performance.
Yes, you should still probably be using RCSI instead of NOLOCK.
(see, no bullets there…even though I could have easily added them)
My Rule of Thumb
- If you need NOLOCK to make a report work, you have a deeper issue
- If you need NOLOCK everywhere, you’re accepting data corruption
- If accuracy matters at all, NOLOCK is the wrong default
Final Thought
The CLR debate taught me something important: Everything in SQL is objectively subjective…wait no…leaving things as they always have been isn’t a valid strategy, and education on new ideas is imperative.
NOLOCK is wildly overused by people who were never shown a better option.
And now you know there is one.















