Oracle-10g
跟踪、調試和修復行鎖爭用
遲到了,我一直面臨著很多行鎖爭用。爭用的表似乎是一個特定的表。
這通常會發生 -
- 開發人員 1 從 Oracle Forms 前端螢幕啟動事務
- 開發人員 2 從使用相同螢幕的不同會話開始另一個事務
大約 5 分鐘後,前端似乎沒有響應。檢查會話顯示行鎖爭用。每個人都拋出的“解決方案”是殺死會話:/
作為數據庫開發人員
- 可以做些什麼來消除行鎖爭用?
- 是否有可能找出儲存過程的哪一行導致這些行鎖爭用
- 減少/避免/消除此類編碼問題的一般準則是什麼?
如果這個問題感覺太開放/資訊不足,請隨時編輯/讓我知道 - 我會盡力添加一些額外的資訊。
有問題的表有很多插入和更新,我會說它是最繁忙的表之一。SP 相當複雜——為了簡化——它從各種表中獲取數據,將其填充到工作表中,在工作表上發生大量算術運算,並將工作表的結果插入/更新到相關表中。
數據庫版本是 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit。邏輯流在兩個會話中以相同的順序執行,事務不會保持打開太久(或者至少我認為是這樣),並且鎖定發生在事務的主動執行期間。
**更新:**表格行數比我預期的要多,大約 310 萬行。此外,在跟踪會話後,我發現該表的幾個更新語句沒有使用索引。為什麼會這樣——我不確定。where 子句中引用的列已編入索引。我目前正在重建索引。
是否有可能找出儲存過程的哪一行導致了這些行鎖爭用?
不完全是,但您可以獲得導致鎖定的 SQL 語句,進而辨識過程中的相關行。
SELECT sid, sql_text FROM v$session s LEFT JOIN v$sql q ON q.sql_id=s.sql_id WHERE state = 'WAITING' AND wait_class != 'Idle' AND event = 'enq: TX - row lock contention';
減少/避免/消除此類編碼問題的一般準則是什麼?
關於鎖的Oracle 概念指南部分說,“只有在寫入者修改行時才會鎖定行”。另一個更新同一行的會話將等待第一個會話
COMMIT
或ROLLBACK
在它可以繼續之前。要消除問題,您可以對使用者進行序列化,但這裡有一些可以將問題減少到不成問題的程度。
COMMIT
更頻繁。每次都會COMMIT
釋放鎖,因此如果您可以批量進行更新,那麼另一個會話需要同一行的可能性就會降低。- 確保在不更改其值的情況下更新任何行。例如,
UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);
應該重寫為更具選擇性(讀更少的鎖)UPDATE t1 SET f1=f1+1 WHERE f2=’a’;
。當然,如果更改語句仍會鎖定表中的大多數行,那麼更改只會帶來可讀性優勢。- 確保您使用的是序列而不是鎖定表以將最高目前值加一。
- 確保您沒有使用導致索引不被使用的函式。如果該函式是必要的,請考慮將其設為基於函式的索引。
- 分組思考。考慮是否可以將執行執行更新的 PL/SQL 塊的循環重寫為單個更新語句。如果不是,那麼也許批量處理可以與
BULK COLLECT ... FORALL
.UPDATE
減少第一個和第一個之間完成的工作COMMIT
。例如,如果程式碼在每次更新後發送一封電子郵件,請考慮將電子郵件排隊並在送出更新後發送。- 設計應用程序以通過執行
SELECT ... FOR UPDATE NOWAIT
or來處理等待WAIT 2
。然後,您可以發現無法鎖定行並通知使用者另一個會話正在修改相同的數據。