If you work with high-concurrency OLTP workloads, SQL Server 2025 Optimized Locking is one of the most practical improvements to understand. In this demo, we use two databases: one with optimized locking disabled and one with it enabled. Both databases are configured with Accelerated Database Recovery (ADR) and Read Committed Snapshot Isolation (RCSI), while only one database has OPTIMIZED_LOCKING = ON.
Why this feature matters
The real value of optimized locking is simple: it helps reduce lock footprint during write activity, which can lower blocking in busy systems. The attached demo is designed exactly for that comparison by creating two identical databases—Billing_OFF and Billing_ON—and toggling only the optimized locking setting between them.
Demo setup
Start by creating the two demo databases and enabling the required database options:
USE master;GODROP DATABASE IF EXISTS Billing_OFF;DROP DATABASE IF EXISTS Billing_ON;GOCREATE DATABASE Billing_OFF;CREATE DATABASE Billing_ON;GO-- Both databases need ADR enabledALTER DATABASE Billing_OFF SET ACCELERATED_DATABASE_RECOVERY = ON;ALTER DATABASE Billing_ON SET ACCELERATED_DATABASE_RECOVERY = ON;GO-- RCSI is needed for lock-after-qualification (LAQ) demoALTER DATABASE Billing_OFF SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;ALTER DATABASE Billing_ON SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;GO-- Only one database gets optimized lockingALTER DATABASE Billing_OFF SET OPTIMIZED_LOCKING = OFF;ALTER DATABASE Billing_ON SET OPTIMIZED_LOCKING = ON;GO-- Verify settingsSELECT name, is_accelerated_database_recovery_on, is_read_committed_snapshot_on, is_optimized_locking_onFROM sys.databasesWHERE name IN ('Billing_OFF', 'Billing_ON');GO
Build the test table
Next, create the same table in both databases and open a transaction so you can inspect locks while the transaction is still active.
Setup for optimized locking OFF
USE Billing_OFF;GODROP TABLE IF EXISTS dbo.InvoiceLedger;GOCREATE TABLE dbo.InvoiceLedger( InvoiceId int NOT NULL, AmountDue decimal(10,2) NULL);GOINSERT INTO dbo.InvoiceLedger (InvoiceId, AmountDue)VALUES (1001, 1200.00), (1002, 850.00), (1003, 430.00);GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 50.00;SELECT request_session_id, resource_type, request_mode, resource_descriptionFROM sys.dm_tran_locksWHERE request_session_id = @@SPID AND resource_type IN ('PAGE', 'RID', 'KEY', 'XACT')ORDER BY resource_type, request_mode;-- Keep transaction open for observationWAITFOR DELAY '00:00:20';COMMIT TRAN;GO
This script updates all rows and keeps the transaction open for 20 seconds so you can inspect the acquired locks in the Billing_OFF database.
Setup for optimized locking ON
USE Billing_ON;GODROP TABLE IF EXISTS dbo.InvoiceLedger;GOCREATE TABLE dbo.InvoiceLedger( InvoiceId int NOT NULL, AmountDue decimal(10,2) NULL);INSERT INTO dbo.InvoiceLedger (InvoiceId, AmountDue)VALUES (1001, 1200.00), (1002, 850.00), (1003, 430.00);GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 50.00;SELECT request_session_id, resource_type, request_mode, resource_descriptionFROM sys.dm_tran_locksWHERE request_session_id = @@SPID AND resource_type IN ('PAGE', 'RID', 'KEY', 'XACT')ORDER BY resource_type, request_mode;WAITFOR DELAY '00:00:20';COMMIT TRAN;GO
This is the matching script for Billing_ON, allowing you to compare lock behavior when optimized locking is enabled.
Concurrency test
To demonstrate blocking behavior, open two sessions against each database.
Session 1 – hold an update open
Optimized locking OFF
USE Billing_OFF;GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 25.00WHERE InvoiceId = 1001;WAITFOR DELAY '00:00:20';COMMIT TRAN;GO
This session updates InvoiceId = 1001 and intentionally holds the transaction for 20 seconds.
Optimized locking ON
USE Billing_ON;GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 25.00WHERE InvoiceId = 1001;WAITFOR DELAY '00:00:20';COMMIT TRAN;GO
This is the same workload pattern, but executed in the database where optimized locking is enabled.
Session 2 – concurrent update
Optimized locking OFF
USE Billing_OFF;GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 25.00WHERE InvoiceId = 1002;COMMIT TRAN;GO
Run this in a second session while Session 1 is still open.
Optimized locking ON
USE Billing_ON;GOBEGIN TRAN;UPDATE dbo.InvoiceLedgerSET AmountDue = AmountDue + 25.00WHERE InvoiceId = 1002;COMMIT TRAN;GO
Again, this is the same concurrent update, but without optimized locking.
Monitoring script
Use the following monitoring query to observe waits, request state, and lock information for both sessions while the demo is running:
-- Replace the session IDs below with the two session IDs used in your demo windows.SELECT r.session_id, r.status, r.command, r.wait_type, r.wait_time, r.wait_resource, t.textFROM sys.dm_exec_requests rCROSS APPLY sys.dm_exec_sql_text(r.sql_handle) tWHERE r.session_id IN (62, 171);GOSELECT request_session_id, resource_type, request_mode, request_status, resource_descriptionFROM sys.dm_tran_locksWHERE request_session_id IN (62, 171)ORDER BY request_session_id, resource_type, request_mode;GO
Expected takeaway
The demo is structured to show that the same update workload behaves differently depending on whether OPTIMIZED_LOCKING is OFF or ON. Because both environments are identically configured except for the optimized locking setting, any change in observed lock behavior is attributable to that feature.
Final thoughts
SQL Server 2025 Optimized Locking is not just a checkbox feature—it directly changes how you demonstrate concurrency, lock management, and blocking reduction to customers. If you want a clean live demo, the attached billing scripts are perfect because they isolate the feature clearly and make the before-vs-after comparison easy to explain.
Watch the Full Demo
I’ve recorded a complete walkthrough of this setup on my YouTube channel JBSWiki. If you’re a visual learner, go check it out!
👉 Watch here: https://www.youtube.com/watch?v=-XQj5YtnuEY
Thank You,
Vivek Janakiraman
Disclaimer:
The views expressed on this blog are mine alone and do not reflect the views of my company or anyone else. All postings on this blog are provided “AS IS” with no warranties, and confers no rights.