oracle lock mode
資料庫是一個多使用者使用的共享資源。當多個使用者併發地存取資料時,在資料庫中就會產生多個事務同時存取同一資料的情況。若對併發操作不加控制就可能會讀取和儲存不正確的資料,破壞資料庫的一致性。
如果是單使用者的系統,那完全沒有必要這個鎖,就是因為有多使用者併發操作,我們為了確保資源的安全性(也就是Oracle的資料完整性和一致性)才引申出這個鎖出來。Oracle 利用其鎖機制來實現事務間的資料併發訪問及資料一致性。
加鎖是實現資料庫併發控制的一個非常重要的技術。當事務在對某個資料物件進行操作前,先向系統發出請求,對其加鎖。加鎖後事務就對該資料物件有了一定的控制,在該事務釋放鎖之前,其他的事務不能對此資料物件進行更新操作。
Oracle的鎖機制是一種輕量級的鎖定機制,不是通過構建鎖列表來進行資料的鎖定管理,而是直接將鎖作為資料塊的屬性,儲存在資料塊首部。
在 Oracle 資料庫中,它並不是對某個表加上鎖或者某幾行加上鎖, 鎖是以資料塊的一個屬性存在的。 也就是說, 每個資料塊本身就儲存著自己資料塊中資料的資訊,這個地方叫 ITL( Interested Transaction List), 凡是在這個資料塊上有活動的事務,它的資訊就會記錄在這裡面供後續的操作查詢,一保證事務的一致性。
在oracle資料庫中,不存在真正意義上屬於某個物件或資料的鎖。oracle鎖的資訊是資料塊的一個物理屬性,而不是邏輯上屬於某個表或某個行。
分類
按使用者和系統分可以分為自動鎖和顯示鎖
自動鎖( Automatic Locks)
當進行一項資料庫操作時,預設情況下,系統自動為此資料庫操作獲得所有有必要的鎖。
自動鎖分為三種:
- DML 鎖
- DDL 鎖
- systemlocks。
顯示鎖( Manual Data Locks)
某些情況下,需要使用者顯示的鎖定資料庫操作要用到的資料,才能使資料庫操作執行得更好,顯示鎖是使用者為資料庫物件設定的。
按鎖級別分可以分為排它鎖和共享鎖
排他鎖(exclusive lock,即X鎖)和共享鎖(share lock,即S鎖)
排他鎖(exclusive lock,即X鎖)
事務設定排它鎖後,該事務單獨獲得此資源,另一事務不能在此事務提交之前獲得相同物件的共享鎖或排它鎖。
共享鎖(share lock,即S鎖)
共享鎖使一個事務對特定資料庫資源進行共享訪問——另一事務也可對此資源進行訪問或獲得相同共享鎖。
共享鎖為事務提供高併發性,但如拙劣的事務設計+共享鎖容易造成死鎖或資料更新丟失。
按操作分可以分為DML鎖、DLL鎖和System Locks
DML鎖
DML 鎖用於控制併發事務中的資料操縱,保證資料的一致性和完整性。
DML鎖主要用於保護併發情況下的資料完整性。
DML 語句能夠自動地獲得所需的表級鎖(TM)與行級(事務)鎖(TX)。
它又分為:
( 1) TM 鎖(表級鎖)
( 2) TX 鎖( 事務鎖或行級鎖)
當 Oracle 執行 DML 語句時,系統自動在所要操作的表上申請 TM 型別的鎖。當 TM 鎖獲得後,系統再自動申請 TX 型別的鎖,並將實際鎖定的資料行的鎖標誌位進行置位。
這樣在事務加鎖前檢查 TX鎖相容性時就不用再逐行檢查鎖標誌,而只需檢查 TM 鎖模式的相容性即可,大大提高了系統的效率。
在資料行上只有 X 鎖(排他鎖)。
在 Oracle 資料庫中,當一個事務首次發起一個 DML 語句時就獲得一個 TX 鎖,該鎖保持到事務被提交或回滾。當兩個或多個會話在表的同一條記錄上執行 DML 語句時,第一個會話在該條記錄上加鎖,其他的會話處於等待狀態。當第一個會話提交後, TX 鎖被釋放,其他會話才可以加鎖。
當 Oracle 資料庫發生 TX 鎖等待時,如果不及時處理常常會引起 Oracle 資料庫掛起,或導致死鎖的發生,產生ORA-600 的錯誤。這些現象都會對實際應用產生極大的危害,如長時間未響應,大量事務失敗等。
TM 鎖用於確保在修改表的內容時,表的結構不會改變,例如防止在 DML 語句執行期間相關的表被移除。當用戶對錶執行 DDL 或 DML 操作時,將獲取一個此表的表級鎖。
當事務獲得行鎖後,此事務也將自動獲得該行的表鎖(共享鎖),以防止其它事務進行 DDL 語句影響記錄行的更新。
事務也可以在進行過程中獲得共享鎖或排它鎖,只有當事務顯示使用 LOCK TABLE 語 句顯示的定義一個排它鎖時,事務才會獲得表上的排它鎖,也可使用 LOCK TABLE 顯示的定義一個表級的共享鎖。
TM 鎖包括了 SS、 SX、 S、 X 等多種模式,在資料庫中用 0-6 來表示。不同的 SQL 操作產生不同型別的 TM 鎖.
TM 鎖型別表
當事務執行資料庫插入、更新、刪除操作時,該事務自動獲得操作表中操作行的排它鎖。
事務發起第一個修改時會得到TX 鎖(事務鎖),而且會一直持有這個鎖,直至事務執行提交(COMMIT)或回滾(ROLLBACK)。
對使用者的資料操縱, Oracle 可以自動為操縱的資料進行加鎖,但如果有操縱授權,則為滿足併發操縱的需要另外實施加鎖。
DML 鎖可由一個使用者程序以顯式的方式加鎖,也可通過某些 SQL 語句隱含方式實現。 這部分屬於 Manual Data Locks。
原理:一個事務要修改塊中的資料,必須獲得該塊中的一個itl,通過itl和undo segment header中的transaction table,可以知道事務是否處於活動階段。事務在修改塊時(其實就是在修改行)會檢查行中row header中的標誌位,如果該標誌位為0(該行沒有被活動的事務鎖住),就把該標誌位修改為事務在該塊獲得的itl的序號,這樣當前事務就獲得了對記錄的鎖定,然後就可以修改行資料了,這也就是oracle行鎖實現的原理。
- 共享鎖方式( SHARE)
- 獨佔鎖方式( EXCLUSIVE)
- 共享更新鎖( SHARE UPDATE)
其中:
SHARE, EXCLUSIVE 用於 TM 鎖(表級鎖)
SHARE UPDATE 用於 TX 鎖( 行級鎖)
共享方式的表級鎖是對錶中的所有資料進行加鎖,該鎖用於保護查詢資料的一致性,防止其它使用者對已加鎖的表進行更新。
其它使用者只能對該表再施加共享方式的鎖,而不能再對該表施加獨佔方式的鎖,共享更新鎖可以再施加,但不允許持有共享更新封鎖的程序做更新。
共享該表的所有使用者只能查詢表中的資料,但不能更新。
共享方式的表級鎖只能由使用者用 SQL 語句來設定.
語句格式如下:
LOCK TABLE <表名>[,<表名>]... IN SHARE MODE [NOWAIT]
- 1
- 1
執行該語句,對一個或多個表施加共享方式的表封鎖。
當指定了選擇項NOWAIT,若該鎖暫時不能施加成功,則返回並由使用者決定是進行等待,還是先去執行別的語句。
持有共享鎖的事務,在出現如下之一的條件時,便釋放其共享鎖:
- A、執行 COMMIT 或 ROLLBACK 語句。
- B、退出資料庫( LOG OFF)。
- C、程式停止執行。
共享方式表級鎖常用於一致性查詢過程,即在查詢資料期間表中的資料不發生改變。
獨佔方式表級鎖是用於加鎖表中的所有資料,擁有該獨佔方式表封鎖的使用者,即可以查詢該表,又可以更新該表,其它的使用者不能再對該表施加任何加鎖(包括共享、獨佔或共享更新封鎖)。
其它使用者雖然不能更新該表,但可以查詢該表。
獨佔方式的表封鎖可通過如下的 SQL 語句來顯示地獲得:
LOCK TABLE <表名>[,<表名>].... IN EXCLUSIVE MODE [NOWAIT]
- 1
- 1
獨佔方式的表級鎖也可以在使用者執行 DML 語句 INSERT、UPDATE、DELETE時隱含獲得。
擁有獨佔方式表封鎖的事務,在出現如下條件之一時,便釋放該封鎖:
- ( 1)、執行 COMMIT 或 ROLLBACK 語句。
- ( 2)、退出資料庫( LOG OFF)
- ( 3)、程式停止執行。
獨佔方式封鎖通常用於更新資料,當某個更新事務涉及多個表時,可減少發生死鎖.
共享更新加鎖是對一個表的一行或多行進行加鎖,因而也稱作行級加鎖。表級加鎖雖然保證了資料的一致性,但卻減弱了操作資料的並行性。
行級加鎖確保在使用者取得被更新的行到該行進行更新這段時間內不被其它使用者所修改。
因而行級鎖即可保證資料的一致性又能提高資料操作的迸發性。
可通過如下的兩種方式來獲得行級封鎖:
( 1)、執行如下的 SQL 封鎖語句,以顯示的方式獲得:
-
LOCK TABLE < 表 名 >[,< 表 名 >].... IN SHARE UPDATE MODE
-
[NOWAIT]
- 1
- 2
- 1
- 2
( 2)、用如下的 SELECT …FOR UPDATE 語句獲得:
-
SELECT <列名 >[,<列名 >]...FROM <表名 > WHERE <條件 > FOR
-
UPDATE OF <列名>[,<列名>].....[NOWAIT]
- 1
- 2
- 1
- 2
一旦使用者對某個行施加了行級加鎖,則該使用者可以查詢也可以更新被加鎖的資料行,其它使用者只能查詢但不能更新被加鎖的資料行.
如果其它使用者想更新該表中的資料行,則也必須對該表施加行級鎖.即使多個使用者對一個表均使用了共享更新,但也不允許兩個事務同時對一個表進行更新,真正對錶進行更新時,是以獨佔方式鎖表,一直到提交或復原該事務為止。
行鎖永遠是獨佔方式鎖。
當出現如下之一的條件,便釋放共享更新鎖:
- ( 1)、執行提交( COMMIT)語句;
- ( 2)、退出資料庫( LOG OFF)
- ( 3)、程式停止執行。
執行 ROLLBACK 操作不能釋放行鎖。
DLL鎖( dictionary locks)
DDL 鎖用於保護資料庫物件的結構,如表、索引等的結構定義。
DDL 鎖又可以分為:
- 排它 DDL 鎖、
- 共享 DDL 鎖、
- 分析鎖
建立、修改、刪除一個數據庫物件的 DDL 語句獲得操作物件的 排它鎖。
如使用 alter table 語句時,為了維護資料的完成性、一致性、合法性,該事務獲得一排它 DDL 鎖
需在資料庫物件之間建立相互依賴關係的 DDL 語句通常需共享獲得 DDL鎖。
如建立一個包,該包中的過程與函式引用了不同的資料庫表,當編譯此包時該事務就獲得了引用表的共享 DDL 鎖。
ORACLE 使用共享池儲存分析與優化過的 SQL 語句及 PL/SQL 程式,使執行相同語句的應用速度更快。
一個在共享池中快取的物件獲得它所引用資料庫物件的分析鎖。
分析鎖是一種獨特的 DDL 鎖型別, ORACLE 使用它追蹤共享池物件及它所引用資料庫物件之間的依賴關係。
當一個事務修改或刪除了共享池持有分析鎖的資料庫物件時, ORACLE 使共享池中的物件作廢,下次在引用這條SQL/PLSQL 語 句時, ORACLE 重新分析編譯此語句。
DDL 級加鎖也是由 ORACLE RDBMS 來控制,它用於保護資料字典和資料定義改變時的一致性和完整性。 它是系統在對 SQL 定義語句作語法分析時自動地加鎖,無需使用者幹予。
字典/語法分析加鎖共分三類:
-
( 1)字典操作鎖:
用於對字典操作時,鎖住資料字典,此封鎖是獨佔的,從而保護任何一個時刻僅能對一個字典操作。 -
( 2) 字典定義鎖:
用於防止在進行字典操作時又進行語法分析,這樣可以避免在查詢字典的同時改動某個表的結構。 -
( 3)表定義鎖:
用於一個 SQL 語句正當訪問某個表時,防止字典中與該表有關的專案被修改。
悲觀封鎖和樂觀封鎖
悲觀封鎖
鎖在使用者修改之前就發揮作用:
-
Select ..for update [nowait]
-
Select * from tab1 for update
- 1
- 2
- 1
- 2
使用者發出這條命令之後,oracle將會對返回集中的資料建立行級封鎖,以防止其他使用者的修改。
如果此時其他使用者對上面返回結果集的資料進行dml或ddl操作都會返回一個錯誤資訊或發生阻塞。
- 1:對返回結果集進行update或delete操作會發生阻塞。左下角的時間執行了很久。
- 2:對該表進行ddl操作將會報:Ora-00054:resource busy and acquire with nowait specified.
原因分析 :
此時Oracle已經對返回的結果集上加了排它的行級鎖,所有其他對這些資料進行的修改或刪除操作都必須等待這個鎖的釋放,產生的外在現象就是其他的操作將發生阻塞,這個這個操作commit或rollback.
同樣這個查詢的事務將會對該表加表級鎖,不允許對該表的任何ddl操作,否則將會報出ora-00054錯誤::resource busy and acquire with nowait specified.
悲觀的缺陷是,加鎖的時間可能會很長,這樣可能會長時間的限制其他使用者的訪問,也就是說悲觀鎖的並 發訪問性不好.
栗子
會話A:
在這裡新開一個plsql視窗模擬會話A
-
--建表
-
create table xgj (name varchar2(20));
-
--新增資料
-
insert into xgj values('xiaogongjiang');
-
--提交資料
-
commit ;
-
--使用for update方式獲取排他行級鎖
-
select * from xgj where name='xiaogongjiang' for update ;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
會話B:
在這裡是在plsql中另外新開了一個視窗模擬會話B,不能在同一個會話視窗,否則測試不出來。
alter table xgj add(salary number(5));
- 1
- 1
注意看左下角的時間,會看到已經執行時間了很長時間,如果會話A不提交則會一直等待,A提交後,馬上執行成功。
樂觀封鎖
樂觀的認為資料在select出來到update資料並提交的這段時間資料不會被更改。樂觀鎖多個會話可以同時操作資料。這裡面有一種潛在的危險就是由於被選出的結果集並沒有被鎖定,是存在一種可能被其他使用者更改的可能。因此Oracle仍然建議是用悲觀封鎖,因為這樣會更安全。
比較常見的方式使用版本列來,每次更新時都和舊版本的資料比較。
System Locks
oracle使用不同型別的系統鎖來保護內部資料庫和記憶體結構.
這些機制是使用者無法訪問的。
死鎖
當兩個使用者希望持有對方的資源時就會發生死鎖.
即兩個使用者互相等待對方釋放資源時,oracle認定為產生了死鎖,在這種情況下,將以犧牲一個使用者作為代價,另一個使用者繼續執行,犧牲的使用者的事務將回滾。
場景
1:使用者 1 對 A 表進行 Update,沒有提交。
2:使用者 2 對 B 表進行 Update,沒有提交。
此時雙反不存在資源共享的問題。
3:如果使用者 2 此時對 A 表作 update,則會發生阻塞,需要等到使用者一的事物結束。
4:如果此時使用者 1 又對 B 表作 update,則產生死鎖。此時 Oracle 會選擇其中一個使用者進行會滾,使另一個使用者繼續執行操作。
起因分析
Oracle 的死鎖問題實際上很少見,如果發生,基本上都是不正確的程式設計造成的,經過調整後,基本上都會避免死鎖的發生。
在 Oracle 系統中能自動發現死鎖,並選擇代價最小的,即完成工作量最少的事務予以撤消,釋放該事務所擁有的全部鎖,記其它的事務繼續工作下去。
從系統性能上考慮,應該儘可能減少資源競爭,增大吞吐量,因此使用者在給併發操作加鎖時,應注意以下幾點:
- 1、 對於 UPDATE 和 DELETE 操作,應只鎖要做改動的行,在完成修改後立即提交。
- 2、 當多個事務正利用共享更新的方式進行更新,則不要使用共享封鎖,而應採用共享更新鎖,這樣其它使用者就能使用行級鎖,以增加並行性。
- 3、 儘可能將對一個表的操作的併發事務施加共享更新鎖,從而可提高並行性。
- 4、 在應用負荷較高的期間,不宜對基礎資料結構(表、索引、簇和檢視)進行修改
死鎖後的解決辦法
如果死鎖不能自動釋放,就需要我們手工的 kill session
生成Kill Session語句
- 檢視有無死鎖物件,如有 kill session
-
SELECT 'alter system kill session ''' || sid || ',' || serial# || ''';' "Deadlock"
-
FROM v$session
-
WHERE sid IN (SELECT sid FROM v$lock WHERE block = 1);
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
如果有,會返回類似與如下的資訊:
kill session:
執行
alter system kill session '646,3953';
- 1
- 1
注意: 應當注意對於 sid 在 100 以下的應當謹慎,可能該程序對應某個application,如對應某個事務,可以 kill
檢視導致死鎖的 SQL
-
SELECT s.sid, q.sql_text
-
FROM v$sqltext q, v$session s
-
WHERE q.address = s.sql_address AND s.sid = &sid -- 這個&sid 是第一步查詢出來的
-
ORDER BY piece;
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
執行後,輸入對應的sid即可檢視對應的sql.
如果輸入的sid找不到對應的sql,可以先執行檢視誰鎖了誰(2)的sql, 查到另外一個sid, 根據另外一個sid,會查到對應的sql .
檢視誰鎖了誰
-
SELECT s1.username
-
|| '@'
-
|| s1.machine
-
|| ' ( SID='
-
|| s1.sid
-
|| ' ) is blocking '
-
|| s2.username
-
|| '@'
-
|| s2.machine
-
|| ' ( SID='
-
|| s2.sid
-
|| ' ) '
-
AS blocking_status
-
FROM v$lock l1,
-
v$session s1,
-
v$lock l2,
-
v$session s2
-
WHERE s1.sid = l1.sid
-
AND s2.sid = l2.sid
-
AND l1.BLOCK = 1
-
AND l2.request > 0
-
AND l1.id1 = l2.id1
-
AND l2.id2 = l2.id2;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
或者
-
SELECT
-
LPAD (' ', DECODE (l.xidusn, 0, 3, 0))
-
|| l.oracle_username
-
User_name,
-
o.owner,
-
o.object_name,
-
o.object_type,
-
s.sid,
-
s.serial#
-
FROM v$locked_object l, dba_objects o, v$session s
-
WHERE l.object_id = o.object_id AND l.session_id = s.sid
-
ORDER BY o.object_id, xidusn DESC;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
鎖和阻塞
概念
通常來講,系統如果平時執行正常,突然會停止不動,多半是被阻塞( Blocked)住了。 我們可以通過 v$lock 這張檢視,看檢視阻塞的資訊。
-
SQL> desc v$lock
-
Name Type Nullable Default Comments
-
------- ----------- -------- ------- --------
-
ADDR RAW(8) Y
-
KADDR RAW(8) Y
-
SID NUMBER Y
-
TYPE VARCHAR2(2) Y
-
ID1 NUMBER Y
-
ID2 NUMBER Y
-
LMODE NUMBER Y
-
REQUEST NUMBER Y
-
CTIME NUMBER Y
-
BLOCK NUMBER Y
-
SQL>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
我們關注的比較多的是 request 和 block 欄位。
如果某個 request 列是一個非 0 值,那麼它就是在等待一個鎖。 如果 block 列是1,這個 SID 就持有了一個鎖,並且阻塞別人獲得這個鎖。
這個鎖的型別由 TYPE欄位定義。鎖的模式有 LMODE 欄位定義, ID1 和 ID2 欄位定義了這個鎖的相關資訊。
ID1 相同,就代表指向同一個資源。 這樣就有可能有加鎖者和等待者。
LMODE 的 6 中模式參考上面的 TM 鎖型別表。
可以結合 v$lock
和 v$session
檢視來查詢相關的資訊:
-
SELECT sn.username,
-
m.SID,
-
sn.SERIAL#,
-
m.TYPE,
-
DECODE(m.lmode,
-
0,
-
'None',
-
1,
-
'Null',
-
2,
-
'Row Share',
-
3,
-
'Row Excl.',
-
4,
-
'Share',
-
5,
-
'S/Row Excl.',
-
6,
-
'Exclusive',
-
lmode,
-
LTRIM(TO_CHAR(lmode, '990'))) lmode,
-
DECODE(m.request,
-
0,
-
'None',
-
1,
-
'Null',
-
2,
-
'Row Share',
-
3,
-
'Row Excl.',
-
4,
-
'Share',
-
5,
-
'S/Row Excl.',
-
6,
-
'Exclusive',
-
request,
-
LTRIM(TO_CHAR(m.request, '990'))) request,
-
m.id1,
-
m.id2
-
FROM v$session sn, v$lock m
-
WHERE (sn.SID = m.SID AND m.request != 0)
-
--存在鎖請求,即被阻塞
-
OR (sn.SID = m.SID
-
--不存在鎖請求,但是鎖定的物件被其他會話請求鎖定
-
AND m.request = 0 AND lmode != 4 AND
-
(id1, id2) IN (SELECT s.id1, s.id2
-
FROM v$lock s
-
WHERE request != 0
-
AND s.id1 = m.id1
-
AND s.id2 = m.id2))
-
ORDER BY id1, id2, m.request;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
或者
-
SELECT /*+ rule */
-
s.username,
-
DECODE(l.TYPE, 'TM', 'TABLE LOCK', 'TX', 'ROW LOCK', NULL) lock_level,
-
o.owner,
-
o.object_name,
-
o.object_type,
-
s.sid,
-
s.serial#,
-
s.terminal,
-
s.machine,
-
s.program,
-
s.osuser
-
FROM v$session s, v$lock l, dba_objects o
-
WHERE l.sid = s.sid
-
AND l.id1 = o.object_id(+)
-
AND s.username IS NOT NULL;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
引起阻塞的幾種常見情況
( 1) DML 語句引起阻塞
( 2)外來鍵沒有建立索引
1.DML 語句引起阻塞
當一個會話保持另一個會話正在請求的資源上的鎖定時,就會發生阻塞。被阻塞的會話將一直掛起,直到持有鎖的會話放棄鎖定的資源為止。
4 個常見的 dml 語句會產生阻塞:
- ( 1) INSERT
- ( 2) UPDATE
- ( 3) DELETE
- ( 4) SELECT…FOR UPDATE
Insert 發生阻塞的唯一情況就是使用者擁有一個建有主鍵約束的表。
當 2 個會話同時試圖向表中插入相同的資料時,其中的一個會話將被阻塞,直到另外一個會話提交或會滾。一個會話提交時,另一個會話將收到主鍵重複的錯誤。回滾時,被阻塞的會話將繼續執行。
UPDATE 和 DELETE 當執行 Update 和 delete 操作的資料行已經被另外的會話鎖定時,將會發生阻塞,直到另一個會話提交或會滾。
當一個使用者執行 select..for update 對返回的結果集進行修改時,如
果結果集已經被另一個會話鎖定,此時 Oracle 已經對返回的結果集上加了排它的行級鎖, 所有其他對這些資料進行的修改或刪除操作都必須等待這個鎖的釋放(操作 commit 或 rollback.),產生的外在現象就是其他的操作將發生阻塞.
同樣這個查詢的事務將會對該表加表級鎖,不允許對該表的任何 ddl 操作,否則將會報出 Ora-00054:resource busy and acquire with nowait specified.
可以通過發出 select ... for update nowait
的語句來避免發生阻塞,如果資源已經被另一個會話鎖定,則會返回以下錯誤:Ora-00054:resource busy and acquire with nowait specified.
2.外來鍵沒有建立索引
如果系統中有主,外來鍵引用關係,並且滿足一下三個條件中的任意一個,那麼就應該考慮給外來鍵欄位建立索引,否則系統的效能可能會下降甚至阻塞。
- ( 1) 主表上有頻繁的刪除操作
- ( 2) 主鍵上有頻繁的修改操作。
- ( 3) 業務上經常會出現主表和從表做關聯查詢的情況。
第一和第二個條件操作的時候,主表會在從表上建立一個鎖定,以保證主表主鍵的修改不會導致從表的資料在引用上出現問題,這是一個數據引用完整性的要求。
如果主表上經常出現這樣的刪除或者是對主鍵列進行修改的操作,或者每次操作的記錄數很多,都將會造成從表長時間被鎖定,而影響其他使用者的正常操作。
比如主表每次刪除 1000 行資料,它就需要掃描從表 1000 次,以確定每一行記錄的改變都不會造成從表資料在引用上的不完整。
特別是在 OLAP 系統中,從表經常會是非常巨大的表,在這種情況下,如果從表沒有索引,那麼查詢幾乎是不可想象的。
Latch
latch概述
Latch屬於 System Lock, 用於保護 SGA區中共享資料結構的一種序列化鎖定機制。
Latch 的實現是與作業系統相關的,尤其和一個程序是否需要等待一個latch、需要等待多長時間有關.
Latch 是 Oracle 提供的輕量級鎖資源, 是一種能夠極快地被獲取和釋放的鎖,能快速,短時間的鎖定資源,
Latch用於防止多個併發程序同時修改訪問某個共享資源, 它只工作在 SGA 中, 通常用於保護描述 buffer cache 中 block 的資料結構。
比如 SGA 中,各種資料被反覆從磁碟讀取到記憶體,又被重新寫回到磁碟上,如果有併發的使用者做相同的事情, Oracle 必須使用一種機制,來保證資料在讀取的時候,只能由一個會話來完成,這種保護機制就是 Latch。
-
併發( concurrency): 是說有超過兩個以上的使用者對同樣的資料做修改(可能包括插入,刪除和修改)。
-
並行( parallel): 是說將一件事情分成很多小部分,讓每一部分同時執行,最後將執行結果彙總成最終結果。
與每個 latch 相聯絡的還有一個清除過程,當持有 latch 的程序成為死程序時,該清除過程就會被呼叫。
Latch 還具有相關級別,用於防止死鎖,一旦一個程序在某個級別上得到一個 latch,它就不可能再獲得等同或低於該級別的 latch。
Latch 不會造成阻塞,只會導致等待。 阻塞是一種系統設計上的問題,等待是一種系統資源爭用的問題。
spin概述
比如資料快取中的某個塊要被讀取,我們會獲得這個塊的 latch, 這個過程叫做 spin,另外一個程序恰好要修改這個塊,他也要 spin 這個塊,此時他必須等待,當前一個程序釋放 latch 後才能 spin 住,然後修改, 如果多個程序同時請求的話,他們之間將出現競爭,沒有一個入隊機制,一旦前面程序釋放所定,後面的程序就蜂擁而上,沒有先來後到的概念, 並且這一切都發生的非常快,因為Latch 的特點是快而短暫。
SPIN 與休眠( sleep)
Oracle 選擇了 spin,讓程序繼續佔有 CPU,執行一些空指令,之後繼續請求,繼續 spin,直到達到_spin_count 值,這時會放棄 CPU,進行短暫的休眠,再繼續剛才的動作。
程序休眠的時間也是存在演算法的.休眠的閥值限制由隱含引數_max_exponential_sleep控制, 預設是 2 秒.
如果當前程序已經佔用了別的 Latch,則他的休眠時間不會太長(過長會引起別的程序的 Latch 等待),此時的休眠最大時間有隱含引數_max_sleep_holding_latch 決定, 預設是 4 釐秒.
總之,Latch 獲取的流程: 請求-SPIN-休眠-請求-SPIN-休眠 … … 佔用。
Latch 和 Lock
從某種意義上說, Latch 是記憶體中的資源鎖,資料庫物件(表,索引等)的鎖叫Lock。
Latch 和 Lock 的區別:
-
( 1) . Latch 是對記憶體資料結構提供互斥訪問的一種機制,而 Lock 是以不同的模式來套取共享資源物件,各個模式間存在著相容或排斥,從這點看出, Latch的訪問,包括查詢也是互斥的,任何時候,只能有一個程序能 spin 住記憶體的某一塊,幸好這個過程是相當的短暫,否則系統性能將沒的保障,從 9I 開始,允許多個程序同時查詢相同的記憶體塊。
-
( 2) . Latch 只作用於記憶體中,他只能被當前例項訪問,而 Lock 作用於資料庫物件,在 RAC 體系中例項間允許 Lock 檢測與訪問
-
( 3) . Latch 是瞬間的佔用,釋放, Lock 的釋放需要等到事務正確的結束,他佔用的時間長短由事務大小決定
-
( 4) . Latch 是非入隊的,而 Lock 是入隊的
-
( 5) . Latch 不存在死鎖,而 Lock 中存在。
Latch 爭用
如果發現系統中經常由於 Lock 導致使用者等待
這時需要考慮系統在邏輯設計上是否有問題,比如多使用者對主鍵的刪除或者修改,是否有使用者使用 select … for update 這樣的語法,外來鍵是否建立索引的因素。 這些因素是需要結合系統的業務邏輯性來進行資料庫物件設計的。
如果發現系統慢是因為很多的 Latch 爭用
就要考慮系統及資料庫自身設計上是否存在問題,比如是否使用繫結變數,是否存在熱快,資料儲存引數設計是否合理等因素。
導致 Latch 爭用而等待的原因非常多,記憶體中很多資源都可能存在爭用。
最常見的兩類 latch 爭用如下:
( 1) 共享池中的 Latch 爭用。
( 2)資料緩衝池中的 latch 爭用。
共享池中的 Latch 爭用
共享池中如果存在大量的 SQL 被反覆分析,就會造成很大的 Latch 爭用和長時間的等待, 最常見的現象就是沒有繫結變數。
最常見的集中共享池裡的 Latch 是 library cache。
可以通過一下 SQL 來查詢:
select * from v$latchname where name like 'library cache%';
- 1
- 1
在分析系統性能時,如果看到有 library cache 這樣的 Latch 爭用,就可以斷定是共享池中出現了問題,這種問題基本是由 SQL 語句導致的,比如沒有繫結變數 或者一些儲存過程被反覆分析。
select event,count(*) from v$session_wait group by event;
- 1
- 1
資料緩衝池中的 latch 爭用
訪問頻率非常高的資料塊被稱為熱快( Hot Block),當很多使用者一起去訪問某幾個資料塊時,就會導致一些 Latch 爭用.
最常見的 latch 爭用有:
- ( 1) buffer busy waits
- ( 2) cache buffer chain
這兩個 Latch 的爭用分別發生在訪問資料塊的不同時刻。
產生這些 Latch 爭用的直接原因是太多的會話去訪問相同的資料塊導致熱快問題, 造成熱快的原因可能是資料庫設定導致或者重複執行的 SQL 頻繁訪問一些相同的資料塊導致。
一:管理員賬戶登入oracle ,並檢視賬戶狀態 二:給指定的賬戶加鎖 加鎖之後我們在檢視這個賬戶的狀態,已成功鎖定 三:給指定使用者解鎖 ...