最近在學習【MySQL事務&鎖】這塊知識,一不留神和MSSQL亂竄了~.~數據庫
文章最初是想查看MySQL vs MSSQL在下面環境產生的阻塞現象
會話1開啓事務更新數據還沒有提交->會話2讀取會話1中修改的行->會話3讀取會話1中修改的行
MySQL:會話1阻塞會話2,會話1阻塞會話3
MSSQL:會話1阻塞會話2,會話2阻塞會話3
MySQL同窗對MSSQL的這種阻塞鏈表示很不理解!咱們查看MSSQL中的鎖等待信息,會話2和會話3等待的是同一資源,爲何sys.sysprocesses中顯示會話2阻塞會話3呢?
我也不知道,也不想去深挖。仍是先把MSSQL中簡單SELECT/UPDATE/DELETE操做要申請的鎖梳理清楚~
【Microsoft SQL Server企業級平臺管理實踐】的第9章和第10章詳細介紹了阻塞與死鎖,建議閱讀原文session
使用SQL Server Profiler跟蹤Lock:Acquired、Lock:Released事件,查看語句執行過程當中鎖的申請和釋放過程
使用sp_lock或者sys.dm_tran_locks羅列鏈接持有的鎖信息
下面的分析基於REPEATABLE READ隔離級別,顯式開啓事務,執行SELECT/UPDATE操做,且不提交事務
1、堆表
從第一行開始,依次掃描表中的每一行數據,而後檢查這一行是否是用戶須要的數據,直到最後一行
1.一、SELECT
Profiler跟蹤看到的過程以下:
OBJECT申請IS鎖->PAGE申請IS鎖->RID申請S鎖->不是用戶所需數據/是用戶所需數據->釋放當前RID上的S鎖/不釋放當前RID上的S鎖->下一個RID...->下一個PAGE...
注意:掃描過程會對讀到的每一條記錄加上一個S鎖(若記錄不返回,在讀完這條記錄就釋放)。只要有任何一條記錄上的鎖沒申請到,查詢就會被阻塞
加鎖狀況(sp_lock):表級別加IS鎖;全部PAGE加IS鎖;返回行加S鎖
1.二、UPDATE
Profiler跟蹤看到的過程以下:
OBJECT申請IX鎖->PAGE申請IU鎖->RID申請U鎖->不是用戶所需數據/是用戶所需數據->釋放當前RID上的U鎖/PAGE升級成IX鎖,RID升級成X鎖->下一個RID...->下一個PAGE...
對於UPDATE語句,可簡單理解先作查詢,把須要修改的記錄給找到,而後在這個記錄上作修改。找記錄的動做要加S鎖,找到要修改的記錄後會先加U鎖,再將U鎖升級成X鎖
加鎖狀況(sp_lock):表級別加IX鎖;修改行加X鎖、修改行所在PAGE加IX鎖;其餘PAGE加IU
2、非彙集索引
這裏是指執行計劃使用了非彙集索引
2.一、SELECT
• 返回列在索引中
索引覆蓋了請求所包含的列,不須要訪問表僅須要訪問索引自己
加鎖狀況(sp_lock):表級別加IS鎖;返回行對應索引鍵值加S鎖、返回行對應索引鍵值所在PAGE加IS鎖
• 返回列不在索引中
使用索引鍵值去訪問非彙集索引,而後使用書籤訪問非彙集索引所在表獲取額外的信息
加鎖狀況(sp_lock):表級別加IS鎖;返回行對應索引鍵值加S鎖、返回行對應索引鍵值所在PAGE加IS鎖;返回行加S鎖、返回行所在PAGE加IS鎖
2.二、UPDATE
• 更新非索引列
加鎖狀況(sp_lock):表級別加IX鎖;修改行加X鎖、修改行所在PAGE加IX鎖;修改行對應索引鍵值加U鎖、修改行對應索引鍵值所在PAGE加IU鎖
• 更新索引列
加鎖狀況(sp_lock):表級別加IX鎖;修改行加X鎖、修改行所在PAGE加IX鎖;原索引鍵值要刪除,新索引鍵值要插入,對應兩個KEY加X鎖、索引鍵值所在PAGE加IX鎖
3、彙集索引
3.一、SELECT
加鎖狀況(sp_lock):表級別加IS鎖;返回行加S鎖;返回行所在PAGE加IS鎖
3.二、UPDATE
• 更新非索引列
加鎖狀況(sp_lock):表級別加IX鎖;修改行加X鎖;修改行所在PAGE加IX鎖
• 更新索引列
加鎖狀況(sp_lock):表級別加IX鎖;修改行原鍵值要刪除,新鍵值要插入,對應兩個KEY加X鎖;修改行所在PAGE加IX鎖ide
--隔離級別 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ SET TRANSACTION ISOLATION LEVEL READ COMMITTED --PAGE DBCC IND(AdventureWorks2008R2,'Employee_Demo',-1) DBCC IND(7,981578535,1) DBCC TRACEON (3604) DBCC PAGE(7,1,3792,3) WITH TABLERESULTS --KeyHashValue SELECT * FROM Employee_Demo WHERE %%lockres%% ='(a0c936a3c965)' --有沒有阻塞發生?是何時發生的?在哪一個數據庫上? SELECT spid,kpid,blocked,waittime,s.waitresource,dbid,s.last_batch,status FROM sys.sysprocesses s WHERE spid>50 --如今阻塞發生在哪一個或哪些資源上 SELECT request_session_id ,resource_type ,request_status ,request_mode ,resource_description ,OBJECT_NAME(p.object_id) AS OBJECT_NAME ,i.name index_name FROM sys.dm_tran_locks LEFT JOIN sys.partitions p ON sys.dm_tran_locks.resource_associated_entity_id = p.hobt_id LEFT JOIN sys.indexes i ON p.object_id = i.[object_id] AND p.index_id = i.index_id ORDER BY request_session_id,resource_type