Sql-Server

全域臨時表上持有哪些類型的鎖?

  • May 11, 2019

我想知道是否:

  • 隔離級別為已送出讀
  • 數據被插入、刪除或讀取

與傳統的行儲存表一樣,用於全域臨時表的鎖是相同的鎖(讀取共享,插入/刪除獨占)。

對於臨時表,我相信它在目前上下文中“存在”時不會發生阻塞,因此我無法同時讀取和插入數據。

但是對於全域臨時表,假設我有很多操作——一些正在插入新數據,一些正在刪除數據,還有一些要讀取的數據將被刪除。

假設表的結構是:

GroupID EntityID
1       101
1       102
1       103
2       101
2       104
3       100

這裡是否適用相同的規則

我對這個問題很好奇,想試試看 tempdb 是一個特殊的數據庫,還是就像另一個使用者數據庫一樣,其中應用了預設隔離“已送出讀”。

以下是我執行的查詢:

--Created two tables in tempdb, one named table and second one as gobal tempdb table

select * into tempdb.dbo.msgs from sys.messages


select * into ##msgs from sys.messages

在下一個視窗中對這些表的幾條記錄執行更新查詢

begin tran
go
update dbo.msgs set language_id = 1055 where message_id = 11242
go
update ##msgs set language_id = 1055 where message_id = 11242
go

上述兩個語句都按預期更新了 22 行。

後來我在兩個不同的視窗中對這兩個表執行了 select 語句,到目前為止都被卡住了:

首先選擇查詢

第二次選擇查詢

我注意到在第一個查詢中根本沒有任何記錄出現在螢幕上,而在第二種情況下,8830 條記錄在螢幕上並隨後卡住(不知道為什麼?)但是在這兩種情況下,查詢都被卡住並永遠執行他們正在等待更新完成。這是 MSSQL 數據庫的預設行為所期望的。

我使用 sp_whoisactive 進行了驗證,並且可以看到存在如下數據庫阻塞:

sp_whoisactive 的輸出

詳細資訊提供了它們中的每一個的鎖定資訊。

第一個:

<Database name="tempdb">
 <Objects>
   <Object name="msgs" schema_name="dbo">
     <Locks>
       <Lock resource_type="OBJECT" request_mode="IS" request_status="GRANT" request_count="1" />
       <Lock resource_type="PAGE" page_type="*" request_mode="S" request_status="WAIT" request_count="1" />
     </Locks>
   </Object>
 </Objects>
</Database>

第二:

<Database name="tempdb">
 <Objects>
   <Object name="##msgs" schema_name="dbo">
     <Locks>
       <Lock resource_type="OBJECT" request_mode="IX" request_status="GRANT" request_count="1" />
       <Lock resource_type="PAGE" page_type="*" request_mode="UIX" request_status="GRANT" request_count="22" />
       <Lock resource_type="RID" page_type="*" request_mode="X" request_status="GRANT" request_count="22" />
     </Locks>
   </Object>
   <Object name="msgs" schema_name="dbo">
     <Locks>
       <Lock resource_type="OBJECT" request_mode="IX" request_status="GRANT" request_count="1" />
       <Lock resource_type="PAGE" page_type="*" request_mode="UIX" request_status="GRANT" request_count="22" />
       <Lock resource_type="RID" page_type="*" request_mode="X" request_status="GRANT" request_count="22" />
     </Locks>
   </Object>
 </Objects>
</Database>

第三:

<Database name="tempdb">
 <Objects>
   <Object name="##msgs" schema_name="dbo">
     <Locks>
       <Lock resource_type="OBJECT" request_mode="IS" request_status="GRANT" request_count="1" />
       <Lock resource_type="PAGE" page_type="*" request_mode="S" request_status="WAIT" request_count="1" />
     </Locks>
   </Object>
 </Objects>
</Database>

還使用以下命令交叉檢查每個事務的隔離級別:

SELECT CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'ReadUncommitted' 
WHEN 2 THEN 'ReadCommitted' 
WHEN 3 THEN 'Repeatable' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL 
FROM sys.dm_exec_sessions 
where session_id in(63,66,67)

結果:

隔離級別

有了所有這些,可以說對於 tempdb,隔離級別也設置為“已送出讀”,並且規則適用於其他數據庫。

我已經在 MSSQL 2019 版本上執行了這些查詢。

引用自:https://dba.stackexchange.com/questions/237890