SQL Server優化:SQL Server中Nolock關鍵字的用法
1、為什么SQL Server有NOLOCK關鍵字?
SQL Server沒創建一個查詢,都相當于創建一個查詢會話,在不同的查詢分析器里面進行的查詢操作,可能會影響別的查詢會話。比較典型的一個例子,如果你正在使用事務執行某一張表的插入或者操作而沒有正確關閉事務的情況下,會造成別的會話針對該數據表的查詢都會處于阻塞的狀態,從而不能完成查詢的操作。這個時候有兩個解決方案,第一種查詢到阻塞的會話id然后殺掉該會話id,第二種可以使用WITH(NOLOCK)關鍵字忽略掉阻塞的會話直接查詢出結果。
簡單來說NOLOCK關鍵字的作用是防止查詢的時候被別的會話阻塞,從而順利完成查詢的操作。
2、SQL Server有NOLOCK有什么問題
使用NOLOCK關鍵字可以避免阻塞造成無法查詢出數據,但使用該關鍵字會有造成數據臟讀的可能。下面舉個例子:
2.1 創建數據表
- CREATE TABLE [dbo].[userInfo] (
- [id] varchar(32) COLLATE Chinese_PRC_CI_AS NOT NULL,
- [userName] nvarchar(30) COLLATE Chinese_PRC_CI_AS NULL,
- [birthday] [dbo].[birthday] NULL,
- CONSTRAINT [PK__userInfo__3213E83F0505C75D]
- PRIMARY KEY CLUSTERED ([id])
- WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
- IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
- ON [PRIMARY]
- )
- ON [PRIMARY]
- GO
- INSERT INTO [dbo].[userInfo] ([id], [userName], [birthday])
- VALUES ('123', N'小明', '2005-01-02 12:30:00.000');
- INSERT INTO [dbo].[userInfo] ([id], [userName], [birthday])
- VALUES ('125', N'小孫', '2005-01-02 12:30:00.000');
2.2 創建時候 會話id 為58 開啟事務 不關閉事務
- begin tran
- insert into userInfo (id,userName,birthday)
- values ('127','小張','2015-01-02 12:30:00.000')
- --commit tran
2.3 當前會話(58)還可以查詢出數據
事務還沒有提交 此時數據還在內存中,未保存到數據庫當中。
- select * from userInfo
2.4 新建一個查詢會話 當前新建的id是51
- select * from userInfo;
- select * from userInfo WITH(NOLOCK);
2.5 殺掉58會話進程
- declare @spid int
- Set @spid = 58 --鎖表進程
- declare @sql varchar(1000)
- set @sql='kill '+cast(@spid as varchar)
- exec(@sql)
3、NOLOCK使用場景
針對那些被頻繁操作(插入、更新、刪除)的表,使用NOLOCK是非常比較適合的,但要考慮到臟讀的情況。
- 不經常修改的數據表,省掉鎖定表的時間來大大加快查詢速度。
- 數據量非常大的數據表,可以考慮犧牲數據安全性來提升查詢的效率;
- 允許出現臟讀現象的業務邏輯,對數據完整性要求比較嚴格的場景不適合,比如電商、銀行等系統。
- 當使用NoLock時,它允許閱讀那些已經修改但是還沒有結束事務的數據。因此要考慮transaction事務數據的實時完整性時,不建議使用。
4、nolock和with(nolock)的區別
三種查詢寫法
- SELECT * FROM A NOLOCK;
- SELECT * FROM A (NOLOCK);
- SELECT * FROM A WITH(NOLOCK);
- SQL Server 2005版本中,只支持with(nolock)關鍵字
- with(nolock)的寫法非常容易再指定索引
- 跨數據庫服務器查詢語句時不能用with (nolock) 只能用nolock,同數據服務器查詢時 兩者都可以用-- SQL Server 2008版本之后建議采用WITH(NOLOCK)寫法。
5、表解鎖腳本
- -- 查詢被鎖表
- select request_session_id spid
- ,OBJECT_NAME(resource_associated_entity_id) tableName
- from sys.dm_tran_locks where resource_type='OBJECT';
- --參數說明 spid 鎖表進程 ;tableName 被鎖表名
- -- 解鎖語句 需要拿到spid然后殺掉縮表進程
- declare @spid int
- Set @spid = 57 --鎖表進程
- declare @sql varchar(1000)
- set @sql='kill '+cast(@spid as varchar)
- exec(@sql)
本文轉載自微信公眾號「IT技術分享社區」,可以通過以下二維碼關注。轉載本文請聯系IT技術分享社區公眾號。
個人博客網站:https://programmerblog.xyz