Sql-Server

基於未索引列的 UPDATE WHERE 中的表掃描如何工作?

  • May 15, 2015

我正在研究由兩個並發 UPDATE 語句引起的死鎖:

UPDATE [table] 
SET [column] = 0 
WHERE [unindexed_column] = @id

我的理解是,因為所基於的列WHERE是未索引的,所以會執行全表掃描。對於每一行,獲取一個更新鎖。如果它匹配該WHERE子句,則升級為排他鎖並持有它直到語句完成。

當會話 A 在第 2 行上具有排他鎖並試圖在第 1 行上獲取更新鎖時,會發生死鎖,而會話 B 在第 1 行上具有排他鎖並試圖在第 2 行上獲取更新鎖。

死鎖的原因是有道理的,但我不完全了解如何執行表掃描以使這種情況成為可能。如果兩個查詢以相同的順序執行掃描,最壞的情況似乎是其中一個查詢在獲取更新鎖時被阻塞,直到另一個查詢完成並釋放它的鎖。

如何執行表掃描?表格行的掃描順序是否不一致?如果更新語句獲取更新鎖失敗,是否會轉到下一行,稍後再嘗試上一行?究竟是什麼使這種僵局成為可能?

表掃描的順序永遠無法保證。也不保證鎖定行的順序。此外,SQL Server 具有鎖升級功能,因此您無法真正說出引擎決定鎖定的內容、行、頁或表本身。

因此,即使並發會話中@id 的值不同,也可能發生死鎖,但感興趣的行恰好位於相同的頁面上。在 SQL Server 2008 及更高版本中,您可以添加ROWLOCK減少鎖升級機會的提示(但同樣不能保證)。如果UPDATE無法獲取鎖,它會等待(LOCK_TIMEOUT指定它會等待多長時間)。

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