oracle-數據庫的各類-鎖-詳解

數據庫是一個多用戶使用的共享資源。當多個用戶併發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的狀況。若對併發操做不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性。mysql

若是是單用戶的系統,那徹底沒有必要這個鎖,就是由於有多用戶併發操做,咱們爲了確保資源的安全性(也就是Oracle的數據完整性和一致性)才引伸出這個鎖出來。Oracle 利用其鎖機制來實現事務間的數據併發訪問及數據一致性。算法

加鎖是實現數據庫併發控制的一個很是重要的技術。當事務在對某個數據對象進行操做前,先向系統發出請求,對其加鎖。加鎖後事務就對該數據對象有了必定的控制,在該事務釋放鎖以前,其餘的事務不能對此數據對象進行更新操做。sql

Oracle的鎖機制是一種輕量級的鎖定機制,不是經過構建鎖列表來進行數據的鎖定管理,而是直接將鎖做爲數據塊的屬性,存儲在數據塊首部。數據庫

在 Oracle 數據庫中,它並非對某個表加上鎖或者某幾行加上鎖, 鎖是以數據塊的一個屬性存在的。 也就是說, 每一個數據塊自己就存儲着本身數據塊中數據的信息,這個地方叫 ITL( Interested Transaction List), 凡是在這個數據塊上有活動的事務,它的信息就會記錄在這裏面供後續的操做查詢,一保證事務的一致性。緩存

在oracle數據庫中,不存在真正意義上屬於某個對象或數據的鎖。oracle鎖的信息是數據塊的一個物理屬性,而不是邏輯上屬於某個表或某個行。安全


分類

按用戶和系統分能夠分爲自動鎖和顯示鎖

自動鎖( Automatic Locks)

當進行一項數據庫操做時,缺省狀況下,系統自動爲此數據庫操做得到全部有必要的鎖。session

自動鎖分爲三種:數據結構

  • DML 鎖
  • DDL 鎖
  • systemlocks。

顯示鎖( Manual Data Locks)

某些狀況下,須要用戶顯示的鎖定數據庫操做要用到的數據,才能使數據庫操做執行得更好,顯示鎖是用戶爲數據庫對象設定的。併發


按鎖級別分能夠分爲排它鎖和共享鎖

排他鎖(exclusive lock,即X鎖)和共享鎖(share lock,即S鎖)oracle

排他鎖(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 鎖(表級鎖)

TM 鎖用於確保在修改表的內容時,表的結構不會改變,例如防止在 DML 語句執行期間相關的表被移除。當用戶對錶執行 DDL 或 DML 操做時,將獲取一個此表的表級鎖。

當事務得到行鎖後,此事務也將自動得到該行的表鎖(共享鎖),以防止其它事務進行 DDL 語句影響記錄行的更新。

事務也能夠在進行過程當中得到共享鎖或排它鎖,只有當事務顯示使用 LOCK TABLE 語 句顯示的定義一個排它鎖時,事務纔會得到表上的排它鎖,也可以使用 LOCK TABLE 顯示的定義一個表級的共享鎖。

TM 鎖包括了 SS、 SX、 S、 X 等多種模式,在數據庫中用 0-6 來表示。不一樣的 SQL 操做產生不一樣類型的 TM 鎖.

TM 鎖類型表 
這裏寫圖片描述


TX 鎖( 事務鎖或行級鎖)

當事務執行數據庫插入、更新、刪除操做時,該事務自動得到操做表中操做行的排它鎖。

事務發起第一個修改時會獲得TX 鎖(事務鎖),並且會一直持有這個鎖,直至事務執行提交(COMMIT)或回滾(ROLLBACK)。

對用戶的數據操縱, Oracle 能夠自動爲操縱的數據進行加鎖,但若是有操縱受權,則爲知足併發操縱的須要另外實施加鎖。

DML 鎖可由一個用戶進程以顯式的方式加鎖,也可經過某些 SQL 語句隱含方式實現。 這部分屬於 Manual Data Locks。

原理:一個事務要修改塊中的數據,必須得到該塊中的一個itl,經過itl和undo segment header中的transaction table,能夠知道事務是否處於活動階段。事務在修改塊時(其實就是在修改行)會檢查行中row header中的標誌位,若是該標誌位爲0(該行沒有被活動的事務鎖住),就把該標誌位修改成事務在該塊得到的itl的序號,這樣當前事務就得到了對記錄的鎖定,而後就能夠修改行數據了,這也就是oracle行鎖實現的原理。

DML 鎖有以下三種加鎖方式:

  • 共享鎖方式( SHARE)
  • 獨佔鎖方式( EXCLUSIVE)
  • 共享更新鎖( SHARE UPDATE) 
    其中: 
    SHARE, EXCLUSIVE 用於 TM 鎖(表級鎖) 
    SHARE UPDATE 用於 TX 鎖( 行級鎖)

共享方式的表級鎖( Share)

共享方式的表級鎖是對錶中的全部數據進行加鎖,該鎖用於保護查詢數據的一致性,防止其它用戶對已加鎖的表進行更新。

其它用戶只能對該表再施加共享方式的鎖,而不能再對該表施加獨佔方式的鎖,共享更新鎖能夠再施加,但不容許持有共享更新封鎖的進程作更新。

共享該表的全部用戶只能查詢表中的數據,但不能更新。

共享方式的表級鎖只能由用戶用 SQL 語句來設置.

語句格式以下:

LOCK TABLE <表名>[,<表名>]... IN SHARE MODE [NOWAIT]
  • 1
  • 1
  • 1

執行該語句,對一個或多個表施加共享方式的表封鎖。

當指定了選擇項NOWAIT,若該鎖暫時不能施加成功,則返回並由用戶決定是進行等待,仍是先去執行別的語句。

持有共享鎖的事務,在出現以下之一的條件時,便釋放其共享鎖:

  • A、執行 COMMIT 或 ROLLBACK 語句。
  • B、退出數據庫( LOG OFF)。
  • C、程序中止運行。

共享方式表級鎖經常使用於一致性查詢過程,即在查詢數據期間表中的數據不發生改變。


獨佔方式表級鎖( Exclusive)

獨佔方式表級鎖是用於加鎖表中的全部數據,擁有該獨佔方式表封鎖的用戶,便可以查詢該表,又能夠更新該表,其它的用戶不能再對該表施加任何加鎖(包括共享、獨佔或共享更新封鎖)。

其它用戶雖然不能更新該表,但能夠查詢該表。

獨佔方式的表封鎖可經過以下的 SQL 語句來顯示地得到:

LOCK TABLE <表名>[,<表名>].... IN EXCLUSIVE MODE [NOWAIT]
  • 1
  • 1
  • 1

獨佔方式的表級鎖也能夠在用戶執行 DML 語句 INSERT、UPDATE、DELETE時隱含得到。

擁有獨佔方式表封鎖的事務,在出現以下條件之一時,便釋放該封鎖:

  • ( 1)、執行 COMMIT 或 ROLLBACK 語句。
  • ( 2)、退出數據庫( LOG OFF)
  • ( 3)、程序中止運行。

獨佔方式封鎖一般用於更新數據,當某個更新事務涉及多個表時,可減小發生死鎖.


共享更新加鎖方式( Share Update)

共享更新加鎖是對一個表的一行或多行進行加鎖,於是也稱做行級加鎖。表級加鎖雖然保證了數據的一致性,但卻減弱了操做數據的並行性。

行級加鎖確保在用戶取得被更新的行到該行進行更新這段時間內不被其它用戶所修改。 
於是行級鎖便可保證數據的一致性又能提升數據操做的迸發性。

可經過以下的兩種方式來得到行級封鎖: 
( 1)、執行以下的 SQL 封鎖語句,以顯示的方式得到:

LOCK TABLE < 表 名 >[,< 表 名 >].... IN SHARE UPDATE MODE [NOWAIT]
  • 1
  • 2
  • 1
  • 2
  • 1
  • 2

( 2)、用以下的 SELECT …FOR UPDATE 語句得到:

SELECT <列名 >[,<列名 >]...FROM <表名 > WHERE <條件 > FOR UPDATE OF <列名>[,<列名>].....[NOWAIT]
  • 1
  • 2
  • 1
  • 2
  • 1
  • 2

一旦用戶對某個行施加了行級加鎖,則該用戶能夠查詢也能夠更新被加鎖的數據行,其它用戶只能查詢但不能更新被加鎖的數據行.

若是其它用戶想更新該表中的數據行,則也必須對該表施加行級鎖.即便多個用戶對一個表均使用了共享更新,但也不容許兩個事務同時對一個表進行更新,真正對錶進行更新時,是以獨佔方式鎖表,一直到提交或復原該事務爲止。

行鎖永遠是獨佔方式鎖。

當出現以下之一的條件,便釋放共享更新鎖:

  • ( 1)、執行提交( COMMIT)語句;
  • ( 2)、退出數據庫( LOG OFF)
  • ( 3)、程序中止運行。

執行 ROLLBACK 操做不能釋放行鎖。


DLL鎖( dictionary locks)

DDL 鎖用於保護數據庫對象的結構,如表、索引等的結構定義。

DDL 鎖又能夠分爲:

  • 排它 DDL 鎖、
  • 共享 DDL 鎖、
  • 分析鎖

排它 DDL 鎖

建立、修改、刪除一個數據庫對象的 DDL 語句得到操做對象的 排它鎖。

如使用 alter table 語句時,爲了維護數據的完成性、一致性、合法性,該事務得到一排它 DDL 鎖


共享 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
  • 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

會話B:

在這裏是在plsql中另外新開了一個窗口模擬會話B,不能在同一個會話窗口,不然測試不出來。

alter table xgj add(salary number(5));
  • 1
  • 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 系統中能自動發現死鎖,並選擇代價最小的,即完成工做量最少的事務予以撤消,釋放該事務所擁有的所有鎖,記其它的事務繼續工做下去。

從系統性能上考慮,應該儘量減小資源競爭,增大吞吐量,所以用戶在給併發操做加鎖時,應注意如下幾點:

  • 一、 對於 UPDATE 和 DELETE 操做,應只鎖要作改動的行,在完成修改後當即提交。
  • 二、 當多個事務正利用共享更新的方式進行更新,則不要使用共享封鎖,而應採用共享更新鎖,這樣其它用戶就能使用行級鎖,以增長並行性。
  • 三、 儘量將對一個表的操做的併發事務施加共享更新鎖,從而可提升並行性。
  • 四、 在應用負荷較高的期間,不宜對基礎數據結構(表、索引、簇和視圖)進行修改

死鎖後的解決辦法

若是死鎖不能自動釋放,就須要咱們手工的 kill session

生成Kill Session語句

  1. 查看有無死鎖對象,若有 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
  • 1
  • 2
  • 3
  • 4

若是有,會返回相似與以下的信息:

這裏寫圖片描述

kill session: 
執行

alter system kill session '646,3953';
  • 1
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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

Insert 發生阻塞的惟一狀況就是用戶擁有一個建有主鍵約束的表。

當 2 個會話同時試圖向表中插入相同的數據時,其中的一個會話將被阻塞,直到另一個會話提交或會滾。一個會話提交時,另外一個會話將收到主鍵重複的錯誤。回滾時,被阻塞的會話將繼續執行。


Update 和 Delete

UPDATE 和 DELETE 當執行 Update 和 delete 操做的數據行已經被另外的會話鎖定時,將會發生阻塞,直到另外一個會話提交或會滾。


Select …for update

當一個用戶執行 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
  • 1

這裏寫圖片描述

在分析系統性能時,若是看到有 library cache 這樣的 Latch 爭用,就能夠判定是共享池中出現了問題,這種問題基本是由 SQL 語句致使的,好比沒有綁定變量 或者一些存儲過程被反覆分析。

資源的爭用能夠經過以下 SQL 來查看

select event,count(*) from v$session_wait group by event;
  • 1
  • 1
  • 1

這裏寫圖片描述


數據緩衝池中的 latch 爭用

訪問頻率很是高的數據塊被稱爲熱快( Hot Block),當不少用戶一塊兒去訪問某幾個數據塊時,就會致使一些 Latch 爭用.

最多見的 latch 爭用有:

  • ( 1) buffer busy waits
  • ( 2) cache buffer chain

這兩個 Latch 的爭用分別發生在訪問數據塊的不一樣時刻。

產生這些 Latch 爭用的直接緣由是太多的會話去訪問相同的數據塊致使熱快問題, 形成熱快的緣由多是數據庫設置致使或者重複執行的 SQL 頻繁訪問一些相同的數據塊致使。

相關文章
相關標籤/搜索