当前位置: 首页 > 科技观察

SQLServer优化:SQLServer中Nolock关键字的用法

时间:2023-03-14 00:17:00 科技观察

1.为什么SQLServer有NOLOCK关键字?SQLServer不创建查询,这相当于创建一个查询会话,而查询在不同的查询分析器中执行的操作可能会影响其他查询会话。一个典型的例子,如果你在使用事务对某个表进行插入或操作,而没有正确关闭事务,就会导致其他会话阻塞对数据表的查询,从而无法完成查询操作。这个时候,有两种解决方法。首先是查询被阻塞的sessionid,然后kill这个sessionid。第二种是使用WITH(NOLOCK)关键字忽略被阻塞的会话,直接查询结果。简单的说,NOLOCK关键字的作用就是防止查询被其他会话阻塞,从而顺利完成查询操作。2、SQLServer的NOLOCK有什么问题?使用NOLOCK关键字可以避免阻塞而无法查询数据,但是使用该关键字可能会导致数据被读脏。下面是一个例子:2.1创建数据表CREATETABLE[dbo].[userInfo]([id]varchar(32)COLLATEChinese_PRC_CI_ASNOTNULL,[userName]nvarchar(30)COLLATEChinese_PRC_CI_ASNULL,[birthday][dbo].[birthday]NULL,约束[PK__userInfo__3213E83F0505C75D]PRIMARYKEYCLUSTERED([id])WITH(PAD_INDEX=OFF,STATISTICS_NORECOMPUTE=OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)ON[PRIMARY]UEINSERTINTTOuser[],[userName],[birthday])'123',N'小明','2005-01-0212:30:00.000');INSERTINTO[dbo].[userInfo]([id],[userName],[生日])VALUES('125',N'Xiaograndson','2005-01-0212:30:00.000');2.2创建时sessionID为58时,启动事务但不关闭事务begintransinsertintouserInfo(id,userName,birthday)values('127','小张','2015-01-0212:30:00.000')--committran2.3当前session(58)还可以检查数据事务还没有提交,数据还在记忆。没有保存到数据库。select*fromuserInfo2.4新建查询session当前id为51select*fromuserInfo;select*fromuserInfoWITH(NOLOCK);2.5kill58sessionprocessdeclare@spidintSet@spid=58--locktableprocessdeclare@sqlvarchar(1000)set@sql='kill'+cast(@spidasvarchar)exec(@sql)3.NOLOCK使用场景对于那些操作频繁的表(insert,update,delete),很适合使用NOLOCK,但是要考虑脏阅读情况。对于不经常修改的数据表,省去了锁表的时间,大大加快了查询速度。对于数据量非常大的数据表,考虑牺牲数据安全性来提高查询效率;允许脏读的业务逻辑不适合对数据完整性要求严格的场景,比如电商、银行等系统。使用NoLock时,它允许读取已修改但尚未结束事务的数据。因此,考虑到交易数据的实时完整性,不建议使用。4.nolock和with(nolock)三种查询写法的区别SELECT*FROMANOLOCK;选择*FROMA(NOLOCK);选择*FROMAWITH(NOLOCK);SQLServer2005版本只支持关键字with(nolock)with(nolock)很容易写在指定的索引中,跨数据库服务器查询时不能使用with(nolock)。你只能使用无锁。查询同一个数据服务器时都可以使用--SQLServer2008以后,推荐使用WITH(NOLOCK)写法。5.表解锁脚本--查询锁表selectrequest_session_idspid,OBJECT_NAME(resource_associated_entity_id)tableNamefromsys.dm_tran_lockswhereresource_type='OBJECT';--参数说明spid锁表过程;tableName是锁表名--unlock语句需要获取spid然后kill它缩表进程declare@spidintSet@spid=57--锁表进程declare@sqlvarchar(1000)set@sql='kill'+cast(@spidasvarchar)exec(@sql)社区”,可通过以下二维码关注。转载本文请联系IT技术分享社区公众号。个人博客站点:https://programmerblog.xyz