SQL Server通過鎖定資源來保證數(shù)據(jù)庫的一致性。SQL Server中的鎖不會對行、頁、表或索引等資源有實際影響,它更像一個預(yù)訂系統(tǒng),所有任務(wù)在數(shù)據(jù)庫內(nèi)預(yù)訂某些資源時都遵守它。過多的鎖或長時間持有的鎖會導(dǎo)致阻塞和其他問題,但鎖本身也可能產(chǎn)生一些問題。
1 解決鎖內(nèi)存問題
為了確定SQL Server中鎖使用的內(nèi)存量,可以監(jiān)視SQL Server中的“鎖內(nèi)存(KB)”計數(shù)器和系統(tǒng)監(jiān)視器(Perfmon)中的“內(nèi)存管理”對象。通過設(shè)置sp_configure中的鎖選項,可以修改SQL Server中鎖的內(nèi)存配額。使用SQLServer:Locks計數(shù)器,可以了解更多關(guān)于鎖行為的細(xì)節(jié)。
如果系統(tǒng)中的鎖內(nèi)存消耗完了,SQL Server不能分配更多的鎖內(nèi)存,session會收到消息1204:
The instance of the SQL Server Database Engine cannot obtain a LOCK resource at this time. Rerun your statement when there are fewer active users. Ask the database administrator to check the lock and memory configuration for this instance, or to check for long-running transactions. |
這個消息說得很清楚:需要增加鎖的內(nèi)存配額,或者減少系統(tǒng)中鎖的數(shù)量。
如果鎖占用很大的內(nèi)存,應(yīng)該首先嘗試找出造成這么多鎖的根本原因。例如,可能是SQL Server的鎖升級不充分。如果是這樣,就需要修改鎖的配置。一旦修改了鎖動態(tài)配置,就影響了鎖升級的行為,由此可能造成意外的影響。
如果數(shù)據(jù)庫不需要任何寫訪問,建議將其設(shè)置為只讀的。這會降低系統(tǒng)中產(chǎn)生的鎖的數(shù)量。在一個只讀的數(shù)據(jù)庫中,SQL Server仍會發(fā)行數(shù)據(jù)庫的共享鎖和讀表的意向共享鎖,但行鎖、頁鎖及SERIALIZABLE隔離級別的行鎖,都不會被發(fā)行。例如,對于只在夜間更新的報表數(shù)據(jù)庫,用戶可以將在白天對數(shù)據(jù)庫的查詢設(shè)置為只讀的。這樣做對鎖內(nèi)存的影響會降低,這也是SQL Server的鎖管理器必須做的。還可以在同一臺服務(wù)器上對只讀數(shù)據(jù)庫創(chuàng)建數(shù)據(jù)庫快照,SQL Server不會在數(shù)據(jù)庫快照上發(fā)行共享鎖。
為了減少鎖內(nèi)存,同樣建議將讀操作與寫操作分開。一種方法是把報表從一個OLTP系統(tǒng)中分開,通過創(chuàng)建報表服務(wù)器和使用事務(wù)復(fù)制或SQL Server集成服務(wù)(SSIS)來為另一個用戶查詢讀操作的服務(wù)器獲取數(shù)據(jù)。這會去掉OLTP主服務(wù)器的共享鎖。如果數(shù)據(jù)庫服務(wù)器能夠支持這種方法,可以考慮用一個數(shù)據(jù)庫快照來定期卸載讀操作。在本章后面我們還可以看到使用一種基于行版本的快照隔離級別來減少讀數(shù)據(jù)查詢產(chǎn)生的鎖。
2 鎖超時
默認(rèn)狀態(tài)下,一個被阻塞的查詢會無限地等待一個未被滿足的鎖的請求。通過使用LOCK_TIMEOUT設(shè)置,可以指定一個session鎖等待的時間。當(dāng)鎖超時發(fā)生時,session會收到消息1222:
Lock request time out period exceeded.
使用LOCK_TIMEOUT給事務(wù)帶來了問題,因為錯誤1222發(fā)生后,SQL Server只是退出當(dāng)前程序語句,而并沒有中止事務(wù)。因此需要在Transact-SQL代碼中使用TRY/CATCH模塊來捕獲1222錯誤。若發(fā)生了超時,可能需要回滾事務(wù)。若要了解更多內(nèi)容,可以參考Inside SQL Server 2005:The Storage Engine(《Microsoft SQL Server 2005:存儲引擎》,電子工業(yè)出版社,2007)第8章的“設(shè)置鎖超時”。