當執行帶有兩個表的JOIN的SELECT語句時,SQL Server似乎是 單獨鎖定了兩個語句的表。例如,通過像 這樣的查詢:SELECT JOIN語句與SQL Server引起的死鎖
SELECT ...
FROM
table1
LEFT JOIN table2
ON table1.id = table2.id
WHERE ...
我發現鎖的順序取決於WHERE條件。查詢優化器會嘗試生成一個執行計劃,根據需要只讀取儘可能多的行數 。因此,如果WHERE條件包含一列表1 它將首先從table1中獲取結果行,然後從table2中獲取相應的 行。如果該列來自table2,它將以 一輪的方式執行此操作。更復雜的條件或使用索引可能會影響查詢優化器的決策。
如果語句讀取的數據應該隨後在具有UPDATE語句的事務 中更新,則不保證UPDATE 語句的順序與用於從2個表中讀取數據的順序相匹配。 如果在事務更新 表時另一個事務嘗試讀取數據,則在UPDATE語句之間在 之間執行SELECT語句時,可能會導致死鎖,因爲SELECT不能在第一個表上獲得 的鎖定,也不能在UPDATE獲得第二張桌子上的鎖。對於 例如:
T1: SELECT ... FROM ... JOIN ...
T1: UPDATE table1 SET ... WHERE id = ?
T2: SELECT ... FROM ... JOIN ... (locks table2, then blocked by lock on table1)
T1: UPDATE table2 SET ... WHERE id = ?
兩個表代表一個類型的層次結構,並總是加載到一起。所以它 有意義使用帶JOIN的SELECT加載對象。單獨加載兩個表 不會使查詢優化器有機會找到最佳的執行計劃 。但由於UPDATE語句只能在 時間更新一個表,所以當一個對象被加載而另一個事務更新了對象 時,這可能導致死鎖。對屬於不同類型的 類型層次結構的對象的屬性進行更新時,對象的更新通常會在兩個表上導致更新。
我試圖向SELECT語句添加鎖定提示,但這並不是 更改問題。當 兩個語句試圖鎖定表並且一個SELECT語句以其他語句的相反順序獲取鎖 時,它只會導致SELECT語句中的死鎖。也許可以通過 加載數據進行更新,並始終使用相同的語句強制鎖定爲 。這將防止兩個事務之間的死鎖,即 想要更新數據,但不會阻止只有讀取數據爲 的事務需要具有不同的WHERE條件的事務。
這是迄今爲止唯一的一輪工作,似乎是讀取可能根本沒有鎖 。對於SQL Server 2005,可以使用SNAPSHOT ISOLATION完成。 SQL Server 2000的唯一方法是使用READ UNCOMMITED隔離級別 級別。
我想知道是否有另一種可能性來防止SQL Server 導致這些死鎖?
快照隔離級別? – 2010-09-14 20:58:41
如果這是一個問題,答案是否定的。它發生在所有的隔離級別,除了READ UNCOMMITTED,我沒有測試,因爲我不希望這些事務可以讀取一半更新的數據。 – Reboot 2010-09-14 21:20:12