在數據庫管理系統(DBMS)的領域中,術語“並發性”用於表示不止一個應用程序基本上(從用戶的角度來看)同時訪問同一數據的能力。
因為 DBMS 的主要優點之一就是可以在多個用戶和多個應用程序中共享數據,所以數據庫系統應該提供一種管理並發訪問數據的方法。DBMS 必須確保維護數據的一致狀態和數據的完整性。
取得該效果的一種方法就是實施只串行(serial-only)模式來處理數據庫請求。即每個事務都要等待另一事務(具有更高的優先權或者比它早啟動)完成其工作。然而,對於現在的在線系統和客戶異常來說,這種處理方式所產生的性能水平簡直令人無法接受。
而另一種方法就是,DBMS 可以通過 鎖的方式管理多個應用程序對數據的訪問。鎖是一種軟件機制,用於在維護數據完整性和一致性的同時,允許盡可能大的吞吐量(通過最大限度地並發訪問數據)。
並發性控制的重要性
如果沒有控制並發性的有效方法,就可能損害數據的完整性和一致性。DBMS 必須保護數據庫,防止發生下列狀況:
在維護數據完整性的同時,提供多個應用程序同時訪問數據的能力稱作 並發性控制。
鎖
鎖是一種由 DB2 UDB 用於完成並發性控制的軟件機制。鎖實質上就是一個控制塊,將 DB2 UDB 對象或資源與應用程序關聯起來,並控制其他應用程序如何訪問同一對象或資源。與 DB2 UDB 資源有關聯的應用程序被稱為“持有”或“擁有”該鎖。
通過使用鎖,DB2 UDB(管理該數據庫)可以防止發生上述幾類問題。DB2 UDB 與另一 MVS 地址空間 IRLM 配合管理這些鎖。IRLM 將跟蹤這些鎖及其所有者,以確定應用程序請求的 DB2 UDB 資源是否可用於該類工作。資源可以是 鎖定的或 共享的,這取決於當前資源上的鎖的“持有者”所進行的處理類型,以及請求應用程序所預期的處理類型。
鎖模式
最常用的兩種鎖模式是 共享的和 排他的。共享鎖與只讀操作有關聯,這意味著持有該鎖的應用程序可以讀取數據,而其他應用程序也可以讀取該數據。排他鎖與寫操作有關聯,這意味著持有該鎖的應用程序有資格更新數據,但在鎖所有者完成更新(將修改提交給數據庫)並釋放該鎖之前,其他應用程序無法使用該數據。
DB2 UDB 和 IRLM 使用其他類型和子類型的鎖模式來實現鎖定和並發性控制。您可以在 DB2 UDB Administration 手冊中找到關於這點的更多詳細描述。
鎖定粒度
除了使用各種鎖模式,DB2 UDB 還提供了不同的鎖定級別,用以控制被鎖定數據的范圍。各種級別表示了 DB2 UDB 使用的鎖定粒度,其范圍可以從單個行到整個表空間。DB2 UDB 根據鎖定粒度來使用不同的鎖模式。
具有多種鎖定級別的理由十分簡單。某些應用程序可能要求有權讀取或更新大范圍的數據,而其他應用程序則可能只要求訪問窄得多的范圍。如果只能使用一種鎖定級別,則會降低整個系統性能。例如,一下子鎖定太多數據會強制其他應用程序進行不必要的等待。否則,DB2 UDB 可能使用過多的系統資源,嘗試服務對附加數據資源進行鎖定的附加請求。能夠實現多種級別的鎖粒度可以極大地提高並發性水平。
暫掛
若一個應用程序進程請求一個鎖,而該鎖已被另一應用程序進程所擁有,且不能共享,此時,就稱該進程為 暫掛的。請求應用程序會被掛起,即它將暫時停止運行。鎖請求的優先次序如下:將新來的鎖請求按照接收次序進行排隊。已經持有鎖的應用程序的請求以及進行鎖提升的請求要比新應用程序的請求先得到服務。而在那些分組中,請求次序則為“先進先出(first in,first out,FIFO)”。
超時
當應用程序處於暫掛狀態(見上面)超過了預設的一段時間間隔,那麼就要終止該應用程序。該應用程序被稱為已經超時。在終止該應用程序之前,會在 SQLCA 中收到一條合適的錯誤消息。SQLCA(SQL 通信域)是 SQL 應用程序預留的一塊大小固定的存儲區域,用於從 DB2 UDB 向程序傳遞條件代碼和其他信息。
某些操作,如 COMMIT 和 ROLLBACK,就不能超時。在下面的子標題 RESOURCE TIMEOUT 中,將對決定應用程序進程可以等待資源多長時間的預設時間間隔進行討論。
死鎖
當兩個或更多應用程序每個都持有另一應用程序所需資源上的鎖,沒有這些資源,那些應用程序都無法繼續完成其工作時,這時就會出現死鎖的狀況。
以下是一個簡單的死鎖場景:
在一段預設的時間間隔之後(請參閱標題 DEADLOCK TIME 下面的討論),DB2 UDB 將終止當前工作單元,因為某個應用程序陷入死鎖狀態(通常為所做工作最少的應用程序)。這將釋放終止程序所持有的鎖,並允許剩余的應用程序繼續下去。 DB2 UDB 將向被終止的應用程序的 SQLCA 發送描述性的錯誤消息和信息。
實用程序和命令的並發機制
當 SQL 應用程序使用事務鎖來控制對 DB2 UDB 對象的並發訪問時,DB2 UDB 實用程序和命令可以通過其他方法訪問 DB2 UDB 對象,即 聲明(claim)、放棄(drain)和 兼容性規則。
聲明是指通知 DB2 UDB 當前正在訪問某個特定對象。提交之後,該聲明通常不會繼續存在。為了在下一工作單元裡訪問 DB2 UDB 對象,應用程序需要進行新的聲明。聲明通知 DB2 UDB 當前正關注某個 DB2 UDB 對象,或是該對象上存在活動。只要 DB2 UDB 對象上存在聲明,在釋放那些聲明之前,就不能采取任何放棄(drain)。
放棄(drain)是指通過下列方式來訪問 DB2 UDB 對象的動作:
DB2 UDB 對象上的放棄導致 DB2 UDB 停止(quIEsce)所有當前正聲明該資源的應用程序,其方式為允許它們到達提交點,但阻止它們(或任何其他的應用程序進程)進行新的聲明。Drain 鎖還阻止沖突進程同時放棄(drain)同一對象。
DB2 UDB 一般通過一組兼容性規則來控制實用程序的並發操作。如果兩個實用程序不需要同時以不可兼容的模式訪問相同的 DB2 UDB 對象,就將它們視為是“兼容的”。當一個實用程序作業開始時,DB2 UDB 就檢查系統,查看當前是否有其他任何實用程序正處理同一 DB2 UDB 對象。如果該對象當前未被另一實用程序訪問,或者如果另一執行實用程序是可兼容的,該實用程序才可以繼續。
數據庫設計考慮
取得高度並發性應該是指導 DB2 UDB 數據庫初始設計的目標之一。在創建各個表的同時,可能要考慮許多影響並發性的功能。您可以在實現創建之後再添加某些功能(例如通過更改 DB2 UDB 對象),但另一些功能則無法添加,或者至少需要大量重復操作和/或打亂當前實現。因此,最好是一開始就考慮這些問題。
分區
我極力建議您將較大的表創建為分區表。一個分區表空間只包含單個分區表。要基於分區索引的鍵范圍將該表分成多個分區。每個分區都是作為單獨的數據集(dataset)來創建的,並且可以作為單獨的實體由 DB2 UDB 加以處理。
對於大量的批處理操作(INSERT、UPDATE、DELETE),您可以將大型作業劃分成較小的作業,利用該分區表結構。許多這些較小的作業可以並發運行(對不同的分區進行),以便減少整個批處理操作的占用時間,從而使另一應用程序進程可以更早地訪問該表。
分區表以類似的方式使實用程序作業只作用於所選擇的分區,從而允許其他作業或應用程序進程並發訪問表中的其他分區。在許多情況下,DB2 UDB 實用程序本身就具有利用分區表的能力,而在其他情況下,它只為用戶提供了設計其工作負載的選項,以便支持 DB2 UDB 數據的更高並發性級別。
鎖升級
DB2 UDB 使用升級技術來平衡鎖定性能開銷的並發性需求。當一個應用程序進程持有單個表或表空間上的大量頁面鎖、行鎖或 LOB 鎖時,DB2 UDB 就獲取該資源上的表或表空間鎖,然後釋放該資源上以前的頁面鎖、行鎖或 LOB 鎖。該過程稱作 鎖升級。
如果一個使用分區鎖定(帶有 LOCKPART YES 的 CREATE 或 ALTER)的表上發生鎖升級,那麼,就只升級當前被鎖定的分區,未鎖定的分區仍舊未鎖定。一旦表空間中發生了鎖升級,那麼就要用表空間鎖來鎖定隨後訪問的未鎖定分區。
在執行應用程序時,DB2 UDB 首先使用頁面鎖或行鎖,並且只要該進程訪問相對較少的頁面或行,還會繼續這樣做。當該應用程序訪問許多頁面或行時,DB2 UDB 將變為使用表鎖、表空間鎖或分區鎖。調用鎖升級的准確時間是由 LOCKSIZE 和 LOCKMAX.的值決定的。
LOCKSIZE
LOCKSIZE 是 CREATE/ALTER TABLESPACE 語句的選項,在應用程序進程訪問表空間中的表時,控制 DB2 UDB 獲取的何種類型的鎖(即,它決定該鎖的“大小”,這有時也稱作鎖粒度)。該選項的可以是 LOB、TABLESPACE、TABLE、PAGE、ROW 和 ANY。
CREATE TABLESPACE 語句的 LOCKSIZE 參數默認為 ANY。LOCKSIZE ANY 允許 DB2 UDB 選擇鎖大小。DB2 UDB 通常將 LOCKSIZE PAGE 用於非 LOB 的表,而將 LOCKSIZE TABLESPACE 用於 LOB 表。
我建議在創建表空間時使用該默認值,除非您有理由進行其他選擇。如果您選擇修改 LOCKSIZE,那麼就要根據使用該表空間的應用程序的性能監控結果和並發性特點來做決定。
使用何種大小的鎖
在 DB2 V4 中才開始可以使用行級鎖。之前,數據頁是最小的鎖定單元。I/T 行業中的許多人都假定行鎖是並發性問題的靈丹妙藥,但實際上,它並不能解決所有的並發性問題。在經歷許多鎖等待、死鎖和超時的環境中,它也許提供了較大的改進。但在其他情形下,DB2 UDB 可能在獲取更多鎖上消耗資源,同時無法成比例地提高並發性。
因為 IRLM 獲取、維護和釋放行鎖所需的處理與頁面鎖需要的大致相同,所以關於指定鎖大小的決定其實就是在較高的鎖定開銷與並發性的潛在提高之間進行權衡。
因此,至於是使用頁面鎖還是使用行鎖,這取決於您的數據和應用程序的特點。如果您覺察到使用頁面鎖定級別的表空間的數據頁上存在大量競爭,那麼就請考慮使用行鎖。通過在行級別而非頁面級別上進行鎖定,可以極大地減少與其他應用程序進程的競爭,特別在訪問是在隨機的情況下。
但是,如果多個應用程序正以不同的順序更新某一頁上的相同行,那麼行鎖導致的競爭甚至可能比頁面的還要多。這是因為,通過頁面鎖,第二個以及隨後的應用程序在訪問該頁面之前,都必須等待第一個應用程序完成,而它們就可能超時。通過行鎖,多個應用程序可以同時訪問同一頁上的行,但如果它們試圖訪問相同的行集,就可能死鎖。