雖然說SQL Server數據庫本身提供了很好的鎖管理機制。但是,從某一方面來說,其實數據庫只是一些客戶端應用程序的“傀儡”。這主要是因為客戶端應用程序對服務器上獲取的鎖幾乎有完全的控制能力。客戶端應用程序發出的查詢請求以及對結果的處理方式,往往具有直接的控制能力。所以,如果應用程序在設計上稍有不合理的情況時,就會因為鎖機制而導致阻塞。
如當遇到如下幾種情形時,就可能會導致阻塞情況的發生。
一、客戶端取消查詢後沒有回滾實務。
查詢是大部分應用程序經常發生的作業。但是,用戶通過前台客戶端應用程序查詢後台數據庫時,有時候往往會因為各種原因取消查詢。如用戶打開查詢窗口後,因為死機或者用戶覺得反映速度慢強制取消查詢。但是,當客戶端取消查詢時,若沒有加上回滾事務的語句,則此時,因為用戶已經向服務器發送了查詢請求,所以,後台數據庫中所涉及的表,都已經加L上了鎖。故即使用戶取消查詢後,所有在事務內獲取的鎖都將會保留。此時,若其他用戶也需要查詢這些表或者用戶重新打開查詢窗口想通過輸入查詢條件來提高系統響應速度時,就會發生阻塞的現象。
二、客戶端沒有及時取得所有查詢的結果。
通常情況下,用戶將查詢請求發送到服務器之後,前台應用程序必須立即完成提取所有結果行。如果應用程序沒有提取所有結果行的話,就會產生一個問題。因為只要應用程序沒有及時提取所有結果,鎖可能會留在表上而阻塞其他用戶。既然應用程序已經將SQ語句遞交給服務器,則該應用程序就必須提取所有的結果行。若應用程序不遵循這個原則的話(如因為一時疏漏而沒有配置),就無法從根本上解決阻塞問題。
三、查詢執行時間過長。
有些查詢會耗用比較長的時間。如因為查詢語句設計不合理或者查詢設計到的表與記錄比較多時,都會使得查詢的執行時間加長。如有時候用戶需要對紀錄進行Update或者Delete操作時,如果涉及的行比較多時,就會獲取很多的鎖。這些鎖無論是否最終升級到表鎖,都會阻塞其他查詢。
故通常情況下,不要將長時間運行的決策支持查詢和聯機事務處理查詢混在一起。
當數據庫遇到阻塞時,往往需要檢查應用程序遞交的SQL語句本身,以及檢查與連接管理、所有結果行的處理等有關的應用程序行為。通常情況下,為了避免因鎖沖突所導致的阻塞,筆者有如下建議。
建議一:查詢完成後提取所有的結果行。
有些應用程序為了提高用戶查詢的響應速度,會有選擇的提取所需要的記錄。這個“小聰明”看起來很合理,但是,卻會造成更大的浪費。因為查詢結果沒有及時提取的話,鎖就不能釋放。當其他人查詢數據時,就會發生阻塞。
所以,筆者建議在應用程序設計時,對於數據庫中查詢的記錄要及時的提取。可以通過其他方式,如添加查詢條件、或者後台查詢的方式,來提高查詢的效率。同時,在應用程序層面設置合理的緩存,也可以非常明顯的提高查詢效率。
建議二:在事務執行時不要讓用戶輸入內容。
雖然在事務執性的過程中,可以讓用戶參與進來,以提高互動性。但是,我們數據庫管理員往往不建議這麼做。因為若要用戶在事務執行過程中輸入參數,會延長事務的執行時間。雖然人比較聰明,但是其反應速度仍然沒有電腦那麼快。所以,在執行過程中加入讓用戶參與的過程,會延長事務的等待時間。故除非有特殊的需要,不要在應用程序的執行過程中,提醒用戶輸入參數。一些事務執行必須的參數,最好在事先就提供。如可以通過變量等預先把需要的參數傳入進去。
建議三:使事務盡可能的簡短。
筆者認為,數據庫管理員應該把一些問題簡單化。當某個需求需要很多SQL語句才能夠完成時,不妨把任務進行分解。同時,也把事務分解成一些簡短的事務。
如數據庫中一張產品信息表,其記錄數量有二百萬條。現在處於管理的需要,把一次性更改其中的一百五十萬條記錄時。若通過一個事務進行更改,則其時間會比較長。若其中還牽涉到級聯更新的話,則時間會更長。
針對這種情況,我們就可以學著把事務簡短話。如這個產品信息中,可能有產品類型字段。那麼在更新數據時,我們能否不一次性進行更新。而是通過產品類別字段進行控制,對記錄進行分次更新的。如此每個類別的更新事務所耗用的時間就可能會大大縮短。如此雖然操作的時候,會需要多個步驟。但是,往往可以有效避免阻塞情況的發生,提高數據庫的性能。