How to put NO LOCK for stored procedure T-SQL for all tables
Implementing NO LOCK for All Tables in SQL Server Stored Procedures

Learn how to apply the NOLOCK hint across all tables within a SQL Server stored procedure to improve read performance, understand its implications, and explore best practices.
In SQL Server, concurrency control is managed through various locking mechanisms. While essential for data integrity, excessive locking can lead to performance bottlenecks, especially in read-heavy applications. The NOLOCK
hint (or READ UNCOMMITTED
isolation level) allows a query to read data without acquiring shared locks, meaning it can read data that is currently being modified by other transactions. This can significantly boost read performance by avoiding waits, but it comes with potential risks like reading uncommitted data, duplicate rows, or missing rows.
Understanding NOLOCK and Its Implications
The NOLOCK
hint is a shorthand for setting the transaction isolation level to READ UNCOMMITTED
for a specific table within a query. When applied, your query will not wait for other transactions to release locks, and it will not place shared locks on the data it reads. This behavior is often desirable for reporting or analytical queries where slight data inconsistency is acceptable in exchange for faster results.
However, it's crucial to understand the trade-offs. Reading uncommitted data means you might retrieve data that is later rolled back, leading to 'dirty reads'. You could also encounter 'phantom reads' (new rows appearing in a subsequent read within the same transaction) or 'non-repeatable reads' (rows changing between reads). For applications requiring high data accuracy, NOLOCK
should be used with extreme caution or avoided entirely.
flowchart TD A[Query Execution Start] --> B{Table A: NOLOCK?} B -- Yes --> C[Read Table A (No Shared Lock)] B -- No --> D[Read Table A (Shared Lock)] C --> E{Table B: NOLOCK?} D --> E E -- Yes --> F[Read Table B (No Shared Lock)] E -- No --> G[Read Table B (Shared Lock)] F --> H[Return Results] G --> H H --> I[Query Execution End]
Flowchart illustrating query execution with and without NOLOCK hints.
Applying NOLOCK to All Tables in a Stored Procedure
There are two primary ways to apply NOLOCK
to all tables within a stored procedure: explicitly adding the hint to each table or changing the transaction isolation level for the entire procedure. While the former is more granular, the latter is often preferred for simplicity when all reads within the procedure can tolerate READ UNCOMMITTED
.
Method 1: Explicitly Adding WITH (NOLOCK)
to Each Table
This method involves manually appending WITH (NOLOCK)
to every table reference in your SELECT
statements. This gives you precise control over which tables use NOLOCK
and which do not. It's generally recommended if only specific tables can tolerate dirty reads.
Method 2: Setting Transaction Isolation Level
This approach changes the isolation level for the entire session or transaction within the stored procedure. By setting SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
, all subsequent SELECT
statements in that session (until the isolation level is reset or the session ends) will behave as if NOLOCK
was specified for all tables. This is a more concise way to achieve the desired effect across multiple queries.
CREATE PROCEDURE GetProductInventoryNOLOCKExplicit
AS
BEGIN
SELECT
p.ProductID,
p.ProductName,
s.QuantityAvailable,
l.LocationName
FROM
Products p WITH (NOLOCK)
INNER JOIN
Stock s WITH (NOLOCK) ON p.ProductID = s.ProductID
INNER JOIN
Locations l WITH (NOLOCK) ON s.LocationID = l.LocationID
WHERE
s.QuantityAvailable > 0;
END;
Example of explicitly adding WITH (NOLOCK)
to each table in a stored procedure.
CREATE PROCEDURE GetProductInventoryNOLOCKIsolationLevel
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT
p.ProductID,
p.ProductName,
s.QuantityAvailable,
l.LocationName
FROM
Products p
INNER JOIN
Stock s ON p.ProductID = s.ProductID
INNER JOIN
Locations l ON s.LocationID = l.LocationID
WHERE
s.QuantityAvailable > 0;
-- It's good practice to reset the isolation level if other operations
-- in the same session require stronger consistency.
-- However, for a stored procedure, the isolation level typically resets
-- to the default after the procedure completes.
-- SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- Or your default
END;
Example of setting TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
for a stored procedure.
NOLOCK
or READ UNCOMMITTED
can lead to 'dirty reads', where you might retrieve data that is later rolled back. This can result in incorrect reports or application logic errors. Always evaluate the acceptable level of data inconsistency for your specific use case.Best Practices and Alternatives
While NOLOCK
can be a quick fix for performance issues, it's not a silver bullet. Consider these best practices and alternatives:
- Use Sparingly: Only apply
NOLOCK
where dirty reads are acceptable, typically for non-critical reporting or dashboard data. - Understand the Risks: Be fully aware of the potential for inconsistent data. Communicate these risks to stakeholders if the data is used for business decisions.
- Snapshot Isolation: For SQL Server 2005 and later,
SNAPSHOT
isolation level (orREAD_COMMITTED_SNAPSHOT
) provides a consistent view of the data as it existed at the start of the transaction, without using locks for reads. This is often a superior alternative toNOLOCK
as it avoids dirty reads while still reducing contention. - Proper Indexing: Often, performance issues are due to missing or inefficient indexes. Optimizing your indexes can provide significant performance gains without sacrificing data integrity.
- Query Optimization: Analyze your query execution plans. Sometimes, a poorly written query is the root cause of performance problems, not locking.
- Materialized Views/Indexed Views: For complex, frequently accessed reports, consider creating materialized views (or indexed views in SQL Server) to pre-calculate and store results, reducing the need for real-time queries with
NOLOCK
.
graph TD A[Performance Issue] --> B{Is it a Locking Issue?} B -- Yes --> C{Can tolerate Dirty Reads?} C -- Yes --> D[Use NOLOCK (Cautiously)] C -- No --> E[Consider Snapshot Isolation] E --> F[Review Indexing & Query Optimization] B -- No --> F F --> G[Consider Materialized/Indexed Views] G --> H[Solution Implemented]
Decision tree for addressing SQL Server performance issues related to locking.
READ_COMMITTED_SNAPSHOT
at the database level. This changes the default READ COMMITTED
isolation level to use row versioning instead of shared locks for read operations, providing better concurrency without the dirty read risks of NOLOCK
.