淺談Sybase封鎖原理和解決方法

第一部分 鎖的有關概念

一、鎖的類型
ASE有三種封鎖類型:排它鎖(exclusive lock),簡稱X鎖);共享鎖(share lock,簡稱S鎖);更新鎖(update lock,簡稱U鎖)。這三種鎖的相容矩陣表如下:
 
  ×:表示不兼容。∨:表示兼容。ASE是自動決定加鎖類型的。一般來說,讀(select)操作使用S鎖,寫(update,insert和delete)操作使用X鎖。U鎖是建立在頁級上的,它在一個更新操作開始時獲 5a8 ,當要修改這些頁時,U鎖會升級爲X鎖。

  二、鎖的粒度
  ASE支持三種鎖粒度:表鎖(Table Lock)、頁鎖(Allpage Lock—鎖數據頁和索引頁, Datapage Lock—只鎖數據頁)和行鎖(Datarow Lock—只鎖數據行)。通常行鎖比頁鎖、表鎖的限制更少(或更小)。行鎖只對某一數據行鎖定,頁鎖對本頁的所有行進行鎖定,而表鎖則鎖定整個表。爲了減小用戶間的數據爭用和改進併發性,ASE試圖儘可能地使用行鎖。當ASE決定一個語句將訪問整個表或表的大多數頁時,它用表鎖來提供更有效的鎖定。鎖定策略直接受查詢方案約束,如果update或delete語句沒有可用的索引,它就執行表掃描或請求一個表鎖定。如果update或delete語句使用了索引,它就通過請求頁鎖來開始,如果影響到大多數行,它就要請求表鎖。一旦一個語句積累的頁鎖超過鎖提升閾值,ASE就設法給該對象分配一個表鎖。如果成功了,頁鎖就不再必要了,因此被釋放。表鎖也在頁層提供避免鎖衝突的方法。對於有些命令ASE自動使用表鎖。

  三、死鎖(DEADLOCK)
  簡單地說,有 5a8 個用戶進程,每個進程都在一個單獨的頁或表上有一個鎖。而且每個進程都想在對方進程的頁或表上請求不相容鎖時就會發生“死鎖”。在這種情況下,第一個進程在等待另一進程釋放鎖,但另一進程要等到第一個進程的對象釋放時纔會釋放自己的鎖。

  ASE檢查是否死鎖,並終止事務中CPU時間積累最小的用戶(即最後進入的用戶)。ASE回滾該用戶的事務,並用消息號1205通知有此死鎖行爲的應用程序,然後允許其他用戶進程繼續進行。

  在多用戶情形下,每個用戶的應用程序都應檢查每個修改數據的事務是否有1205號消息,以此確定是否有可能死鎖。消息號1205表示該用戶的事務因死鎖而終止並被回滾。應用程序必須重新開始這個事務處理。


第二部分 查找死鎖原因


  死鎖的發生對系統的性能和吞吐量都有重要影響,經檢測發現,管理信息系統的死鎖主要是因爲兩個或多個線程(登錄)搶佔同 5cc 表數據資源。引起長時間搶佔同一資源不是因爲我們需要處理的事務太複雜,時間太長,而往往是因爲我們在前端應用程序對數據庫作操作時忘了提交。 既然管理信息系統長時間死鎖的原因是由於我們忘了提交或者是提交不當,那麼我們就可以通過修改程序防止出現死鎖。定位死鎖出錯處主要經過以下三步:
  ① 在死鎖出現時,用sp_who,sp_lock獲得進程與鎖的活動情況。
  ② 結合庫表sysobjects和相應的操作員信息表查出被鎖的庫表與鎖住別人的操作員。
  ③ 根據鎖定的庫表與操作員的崗位,可以估計出程序大約出錯處。詢問操作員在死鎖時執行的具體操作即可完全定位出錯處。最後查找程序並修改之。

  下面舉幾個命令應用的實例:
  實例1、用sp_who獲取關於被阻礙進程的信息系統過程,sp_who給出系統進程的報告。如果用戶的命令正被另一進程保持的鎖阻礙,則如圖顯示:

  (說明:status列顯示“lock sleep”。blk列顯示保持該鎖或這些鎖的進程 16a0 識,即被誰鎖定了。loginame列顯示登錄操作員。結合相應的操作員信息表,便可知道操作員是誰。)
  實例2、用sp_lock2瀏覽鎖,要得到關於當前sql server上保持的鎖的報告,可用系統過程sp_lock2 [spid1[,spid2]],spid1,spid2是表master..dbo..sysprocesses中的sql server進程id號,用sp_who可以得到鎖定與被鎖定的spid號,執行該進程後屏幕顯示: 

(說明:locktype列顯示加鎖的類型和封鎖的粒度,有些鎖的後綴還帶有blk表明鎖的狀態。前綴表明鎖的類型:Sh—共享鎖,Ex—排它鎖或更新鎖,中間表明鎖死在表上(table或intent)還是在頁上(page)。 後綴“blk”表明該進程正在障礙另一個需要請求鎖的進程。一旦正在障礙的進程一結束,其他進程就向前移動。“demand”後綴表明當前共享鎖一釋放, 該進程就申請互斥鎖。table_name列顯示錶表名。)


第三部分 ASE關於鎖的系統調優


  一、 調整死鎖檢測間隔
  ① 通過配置參數“print deadlock information”的設置,在ASE的日誌中顯示死鎖發生的情形。
  ② 如果應用很少發生死鎖現象,則可以使用參數deadlock checking period來指定進行死鎖檢查之前進程的等待時間,這樣可以延遲死鎖檢查而降低開銷。 
  ③ deadlock checking period 的取值範圍是0-2147483缺省值是500,即一進程至少等待500ms後,ASE才準備檢查死鎖。

  二、死鎖預防 
  ① 爲儘可能避免死鎖的出現在所有的事務中都按同一順序來訪問各個表。
儘可能利用存儲過程來完成一個事務,以能夠保證對各表的訪問次序都是一致的。除非有“可重複讀”的必要性,否則不要使用holdlock選項。
  ② 事務應縮小且應儘快提交。
  ③ 避免人工輸入操作出現在事務中或是同時對該表施加holdlock。
  ④ 避免併發地執行許多像insert,update,delete這類數據修改語句。

  三、數據庫鎖的配置原則
  ① 鎖的數量不要太小,如果鎖不夠,可通過命令 sp_configure “number of locks”,NUM 進行修改。
  ② 如果需要節省空間,減少維護量,使用所有頁鎖機制。
  ③ 如果需要加快速度,空間足夠,使用數據頁鎖機制。
  ④ 當通過監測發現鎖競爭超過15%時,首先修改加鎖最重的表的鎖機制,然後再把數據頁鎖設置爲數據行鎖。如果發現螺旋鎖多,則爲該表建立單獨的命名緩存並對命名緩存進行分區。
這裏舉兩個有用的實例,可幫助讀者獲取一些系統參數,用於分析是否需要更改參數配置。
實例1:執行sp_sysmon “00:05:00” 系統採樣(報告在5分鐘內關於數據緩衝區統計信息,可確定是否I/O開銷太大等)
DBCC execution completed。 If DBCC printed error messages, contact a user with
System Administrator (SA) role。
Sybase Adaptive Server Enterprise System Performance Report
===============================================================================
Server Version: Adaptive Server Enterprise/11。9。2。6/1290/P/EBF 10487 ESD
Server Name: Server is Unnamed
Run Date: Dec 27, 2005
Statistics Cleared at: 10:46:59
Statistics Sampled at: 10:51:59
Sample Interval: 00:05:00
(以下缺省,如想查看詳細信息,請執行sp_sysmon “00:05:00”)
實例2:執行sp_object_stats “00:05:00”,10,db1(此命令是將5分鐘之內競爭激烈的頭10個表列出來)
Lock statistics for the top 10 (or less) most contended objects:
Object Name: db1..table1 (dbid=7, objid=555305188, lockscheme=Datarows):-
Row Locks SH_ROW UP_ROW EX_ROW
---------- ---------- ---------- ----------
Grants: 969 0 50
Waits: 3 0 0
Deadlocks: 0 0 0
Wait-time: 6790 ms 0 ms 0 ms
Contention: 0。31% 0。00% 0。00%
Object Name: db1..table3 (dbid=7, objid=1927834080, lockscheme=Allpages):-
Page Locks SH_PAGE UP_PAGE EX_PAGE
Grants: 273760 5880 324
Waits: 16 0 0
Deadlocks: 0 0 0
Wait-time: 684 ms 0 ms 0 ms
Contention: 0。01% 0。00% 0。00%
(以下缺省,如想查看詳細信息,請執行sp_object_stats“00:05:00”,10,db1)
從中可看出table3事全頁鎖,table1是數據行鎖,表的競爭都在可接受的範圍內,沒有需要調整的配置。

  四、數據庫鎖的提升機制

  ㈠、提升鎖時幾個命令
  ① ASE中對所有的表都予置了隱含的全頁面加鎖機制,可用命令
sp_configure “lock scheme”,[allpages|datapages|datarows] 查看鎖的類型。當數據庫從原先版本的服務器中轉儲出來重新加載時,所有的表都被定義爲全頁面加鎖的表。
  ② 當建立一個新表時,可以不使用這個 1b68 缺省值,而採用如下的句法格式:
create table <tablename>…lock[allpages|datapages|datarows] 
  ③ 爲了在使用的一個表中改變加鎖類型,可以採用如下的句法格式:
alter table <tablename> lock[allpages|datapages|datarows]
  ㈡、提升鎖時需注意幾個問題
  鎖提升是同類型的提升,Share Page Lock à Share Table Lock,鎖提升的前提條件是在該表上不能有其他類型的鎖,比如表A上有共享頁鎖,當共享頁鎖的數目達到參數“ page lock promotion HWM”的值並且表A上沒有其他的鎖時,會提升到表級共享鎖。在一個現存的表中改變加鎖方式,將引起下列三種行動後果發生:
  首先,如果一張表從全頁加鎖轉變爲僅對數據加鎖,或者從僅對數據加鎖轉變爲全頁加鎖,在這兩種類型之間就要對錶進行選擇以允許進行存貯格式改變。如果這是一個分區表,就要同時假定必要的並行級別和工作線程已經配置好的情況下,才能執行。其次,對錶中的羣聚性索引必須重新創建。因爲我們要保證數據,所以如果從全頁加鎖方式轉換爲只對數據加鎖時,這種重新創建可以通過“with sorted_data”來完成。然而,當從僅對數據加鎖機制轉換爲全頁加鎖方式時,就要進行並行的索引創建操作。(請注意:如果這是一個分區表時,那麼並行等級和工作線程的數目必須加以配置才能允許進行這種改變,否則這種遷移將會失敗)。最後,非羣聚性的索引將被重建。
  由於這些活動同潛在的工作量有關,從全頁加鎖機制改變爲僅對數據加鎖或從僅對數據加鎖改變爲全頁加鎖機制都可能是耗費時間的活動。爲了標註這一點,有以下一些選擇:如果可能的話,應該配置使用並行方式。這至少對執行非羣聚性索引的哈斯(雜湊,即hashed)創建方法是必須的,但是如果可能的話,採用分區表和分區掃描將使系統得到更大的改進。在選擇進入和創建羣聚性的索引之後,該任務將被設置檢查點(checkpointed)。所以如果有充分的硬件資源,通過允許在任何一個時間點上,檢查點任務可以具有多於10個(系統缺省值)的異步I/O請求,利用dbcc進行調諧將能夠帶來有益的效果。(“maxwritedes”,number) 進一步作爲降低使用檢查點成本的一種方法,在相關的高速緩衝池(cache pool)、大數據量的I/O操作中,採用對高淘汰程度進行標記的方法,並允許清潔程序(好象家庭主婦一樣)保持特別活躍的狀態,將爲那些檢查點需要從高速緩衝池中,刷新較“髒”的頁面的而增加的I/O操作次數,並因此花費了在檢查點上的時間都能夠大大減少作出貢獻。如果預先進行了配置,則可以對並行的選擇進入可以使用預先分配的盤區。所以,通過將sp_configure “number of pre-allocated extent”設置爲16也將對系統性能有明顯的積極的效果。

  五、定位出錯處
  根據sp_who與sp_lock2命令的結果,結合sysobjects和相應的操作員的信息表。得到操作員及其在死鎖時所操作的庫表,便大約可以知道應用程序的出錯處,再執行dbcc traceon(3604)以進一步認證。最後查找程序並修正之。 有一段時間,筆者維護的數據庫頻繁出現死鎖,查看數據庫也沒有什麼大的操作,cpu利用率也在合理範圍內,是什麼引起數據庫頻繁死鎖呢,筆者用了以下幾步命令,找到了原因:
  ① select * from master syslogshold 執行後發現有一個進程超過了24小時未釋放(記下進程的spid號),但這個進程執行了什麼命令不能判斷。(syslogshold表記錄最老的仍活動的事務, 要查詢每一數據庫在應用中有最老的活動的事務及其開始時間。)
  ② dbcc traceon(3604) 打開數據庫的開關,設置輸出到屏幕。
  ③ dbcc sqltext(進程號) 這時我們會看到引起阻塞,不能釋放的sql語句。
通過以上三步,筆者當時看到引起阻塞不能釋放的sql語句只是普通的select語句,但是對同一張表反覆提取數據,在對源程序研究後發現在select語句執行後,沒有提交事務的語句(即commit),而該程序被廣泛使用,造成進程阻塞不斷增加,最終導致互鎖。找到問題根源後,及時對程序調優,死鎖現象在未發生。由此也可看出,在沒有進行大的操作時,當進程定義user_transtion 的進程超過60分鐘,就應該檢查應用程序,調整不合理的程序或業務流程。

第四部分 總結


  據我個人多年對數據庫的使用經驗,我覺得對於並行性較高的應用要充分考慮使用行級鎖,這樣對於提高併發性能至關重要!當然,事務都存在利弊兩方面,使用行級鎖,也會帶來一些相應的弊端,比如使用的鎖越多,佔用的內存也越多,在使用行級鎖的表上頻繁的進行數據刪除、插入操作久而久之會造成數據庫碎片的大量生成,數據庫性能會下降,且影響業務。所以在使用行鎖、頁鎖或表鎖時要根據系統硬件和使用情況作出合理的綜合判斷,使數據庫性能達到最優。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章