with(nolock) table hint 不意味着不会加锁,使用 Trace Flag 1200 返回加锁的整个过程,是学习加锁过程的得力工具
DBCC TRACEON(1200,-1) DBCC TRACEON(3604) DBCC TRACESTATUS
Step1,设置事务隔离级别为 Read Committed,然后使用with(nolock) table hint,查看加锁过程
SET TRANSACTION ISOLATION LEVEL READ COMMITTED select * from dbo.test with(nolock) where id=1
在第一次执行该语句时,加锁过程如下
Process 76 acquiring S lock on DATABASE: 12 [PLANGUIDE] (class bit0 ref1) result: OK Process 76 releasing lock on DATABASE: 12 [PLANGUIDE] Process 76 acquiring Sch-S lock on OBJECT: 12:544379958:0 (class bit0 ref1) result: OK Process 76 releasing lock on OBJECT: 12:544379958:0 Process 76 acquiring S lock on DATABASE: 12 [PLANGUIDE] (class bit0 ref1) result: OK Process 76 acquiring S lock on DATABASE: 12 [PLANGUIDE] (class bit0 ref1) result: OK Process 76 acquiring Sch-S lock on OBJECT: 12:560380015:0 (class bit0 ref1) result: OK Process 76 acquiring Sch-S lock on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 0) (class bit0 ref1) result: OK Process 76 acquiring Sch-S lock on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 0) (class bit0 ref1) result: OK Process 76 releasing lock reference on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 0) Process 76 acquiring X lock on OBJECT: 12:560380015:0 [UPDSTATS] (class bit0 ref1) result: OK Process 76 releasing lock on OBJECT: 12:560380015:0 [UPDSTATS] Process 76 acquiring Sch-S lock on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 2) (class bit0 ref1) result: OK Process 76 acquiring Sch-S lock on METADATA: database_id = 12 STATS(object_id = 560380015, stats_id = 2) (class bit0 ref1) result: OK Process 76 acquiring S lock on KEY: 12:281474980642816 (fa51984d2469) (class bit0 ref1) result: OK Process 76 releasing lock on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 2) Process 76 releasing lock on METADATA: database_id = 12 STATS(object_id = 560380015, stats_id = 2) Process 76 releasing lock on METADATA: database_id = 12 INDEXSTATS(object_id = 560380015, index_id or stats_id = 0) Process 76 releasing lock on OBJECT: 12:560380015:0 Process 76 releasing lock reference on DATABASE: 12 [PLANGUIDE] Process 76 releasing lock on DATABASE: 12 [PLANGUIDE] Process 76 acquiring Sch-S lock on OBJECT: 12:560380015:0 (class bit0 ref1) result: OK Process 76 acquiring S lock on HOBT: 12:72057625107234816 [BULK_OPERATION] (class bit0 ref1) result: OK (1 row(s) affected) Process 76 releasing lock on OBJECT: 12:560380015:0
再次执行查询语句时,加锁过程如下
Process 76 acquiring Sch-S lock on OBJECT: 12:560380015:0 (class bit0 ref1) result: OK Process 76 acquiring S lock on HOBT: 12:72057625107234816 [BULK_OPERATION] (class bit0 ref1) result: OK (1 row(s) affected) Process 76 releasing lock on OBJECT: 12:560380015:0
使用With(nolock) table hint,至少会申请Schema 和 HoBT 上的共享锁。
To Quota:“WITH (NOLOCK)” doesn’t actually mean no locking.
At some point in your career, you’re going to start using WITH (NOLOCK) on everything because it gets your query results faster. That’s not necessarily a bad idea, but it can come with some surprising side effects that Kendra discusses in her “There’s Something About Nolock” video. I’m going to focus on one of them here, though.
When you query a table – even WITH (NOLOCK) – you take out a schema stability lock. No one else can change that table or indexes until your query is finished. That doesn’t sound like a big deal until you need to drop an index, but you can’t because people are constantly querying a table, and they think there’s no overhead as long as they use WITH (NOLOCK).
There’s no silver bullet here, but start by reading about SQL Server’s isolation levels – I bet READ COMMITTED SNAPSHOT ISOLATION is an even better choice for your app. It gets you consistent data with less blocking hassles.