2010-03-06 87 views
2

,這是爲什麼,與SQL Server(所以事務隔離級別=提交讀)默認設置,這個測試:解釋在SQL Server的鎖定行爲

CREATE TABLE test2 (
ID bigint, 
name varchar(20) 
) 

然後在一個SSMS運行此標籤:

begin transaction SH 
insert into test2(ID,name) values(1,'11') 
waitfor delay '00:00:30' 
commit transaction SH 

,這一次同時在另一個標籤:

select * from test2 

需要第二個選擇等待第一個完成之前返回??

我們也嘗試了這些用於第二查詢:

select * from test2 NOLOCK WHERE ID = 1 

,並試圖在第一個查詢插入一個ID和在所述第二選擇不同的ID。

這是頁面鎖定的結果嗎?當運行2個查詢,我也跑了這一點:

select object_name(P.object_id) as TableName, resource_type, resource_description 
from 
sys.dm_tran_locks L join sys.partitions P on L.resource_associated_entity_id = p.hobt_id 

,並得到這個結果集:

test2的RID 1:12186:5
test2的RID 1:12186:5
TEST2 PAGE 1:12186
TEST2 PAGE 1:12186

+0

您使用的是什麼版本的SQL Server?從2000年起,SQL Server默認使用行級鎖 - 而不是頁鎖。 – 2010-03-06 21:25:14

回答

4

要求第二次選擇等待 第一次完成之前 返回

讀COMMITED防止髒讀,並通過阻止你將得到一個一致的結果,快照隔離來解決這個,但你會得到表現略差,因爲現在的SQL Server將持有舊值交易的持續時間(更你有一個很好的驅動器上的tempdb)

BTW,嘗試從

select * from test2 

更改查詢到

select * from test2 where id <> 1 

假設你在表中有超過1行,這將是在一個頁面,插入幾千行

+0

+1,這是一個**功能**,而不是一個錯誤,跳過「髒」的插入,直到他們已經承諾! :-) – 2010-03-06 21:14:07

3
與節點鎖定

目錄遍歷由「捕蟹」來完成:

  • 你有一個鎖定當前節點
  • 你搶鎖定下一個節點
  • 您做出下一個節點當前
  • 放開前一個節點上的鎖(前者電流)

這種技術在所有列表遍歷算法中都很常見,並且意味着在遍歷期間保持穩定性:您永遠不會在沒有鎖定的情況下進行「跳躍」。它通常與攀巖者使用的技術相比較。

SELECT ... FROM table;這樣的聲明是對整個表格的掃描。因此,它可以與列表遍歷進行比較,並且執行表掃描遍歷的線程將對行進行「crabb」,就像執行列表遍歷將在節點上執行一樣。這樣的列表遍歷是保證,它將試圖最終鎖定列表中的每個單個節點,並且表掃描將類似地嘗試鎖定表中的每一行。因此,另一筆交易在行上持有的衝突鎖將阻止掃描,100%保證。你觀察到的其他一切(頁面鎖,意圖鎖等)都是實現細節,與基本問題無關。

此問題的正確解決方案是優化他們不掃描表端到端的查詢。之後只有可以實現,您可以將注意力轉移到消除所有剩餘爭用:部署基於row-level versionning的快照隔離。換句話說,啓用數據庫上的讀取提交快照。