共計(jì) 3200 個(gè)字符,預(yù)計(jì)需要花費(fèi) 8 分鐘才能閱讀完成。
本篇內(nèi)容介紹了“Latch 和 Lock 的區(qū)別是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓丸趣 TV 小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
本文向各位闡述 Oracle 的 Latch 機(jī)制,Latch,用金山詞霸翻譯是門插栓,閉鎖,專業(yè)術(shù)語叫鎖存器,我開始接觸時(shí)就不大明白為什么不寫 Lock,不都是鎖嗎? 只是翻譯不同而以? 研究過后才知道兩者有很大的區(qū)別。
Oracle 中鎖的信息是數(shù)據(jù)塊的一部分,是物理的,并不是邏輯上屬于某個(gè)表或者某個(gè)行。Latch 是 Oracle 提供的輕量級(jí)鎖資源,他用于快速,短時(shí)間的鎖定資源,防止多個(gè)并發(fā)進(jìn)程同時(shí)修改訪問某個(gè)共享資源,他只工作在內(nèi)存中,我們可以不大準(zhǔn)確的說,內(nèi)存中資源的鎖叫 latch,數(shù)據(jù)庫對(duì)象 (表,索引等) 的鎖叫 Lock。比如數(shù)據(jù)緩存中的某個(gè)塊要被讀取,我們會(huì)獲得這個(gè)塊的 latch,這個(gè)過程叫做 pin,另外一個(gè)進(jìn)程恰好要修改這個(gè)塊,他也要 pin 這個(gè)塊,此時(shí)他必須等待,當(dāng)前一個(gè)進(jìn)程釋放 latch 后才能 pin 住,然后 修改,如果多個(gè)進(jìn)程同時(shí)請(qǐng)求的話,他們之間將出現(xiàn)競(jìng)爭,沒有一個(gè)入隊(duì)機(jī)制,一旦前面進(jìn)程釋放所定,后面的進(jìn)程就蜂擁而上,沒有先來后到的概念,這個(gè)和 Lock 是有本質(zhì)區(qū)別的,這一切都發(fā)生的非常快,因?yàn)?Latch 的特點(diǎn)是快而短暫,當(dāng)然這個(gè)只是大致過程,細(xì)節(jié)部分在后面討論
先來看下 Latch 和 Lock 的區(qū)別,
1. Latch 是對(duì)內(nèi)存數(shù)據(jù)結(jié)構(gòu)提供互斥訪問的一種機(jī)制,而 Lock 是以不同的模式來套取共享資源對(duì)象,各個(gè)模式間存在著兼容或排斥,從這點(diǎn)看出,Latch 的訪問,包括查詢也是互斥的,任何時(shí)候,只能有一個(gè)進(jìn)程能 pin 住內(nèi)存的某一塊,幸好這個(gè)過程是相當(dāng)?shù)亩虝海駝t系統(tǒng)性能將沒的保障,現(xiàn)在從 9I 開始,允 許多個(gè)進(jìn)程同時(shí)查詢相同的內(nèi)存塊,但性能并沒有想象中的好。
2. Latch 只作用于內(nèi)存中,他只能被當(dāng)前實(shí)例訪問,而 L ock 作用于數(shù)據(jù)庫對(duì)象,在 RAC 體系中實(shí)例間允許 Lock 檢測(cè)與訪問
3. Latch 是瞬間的占用,釋放,Lock 的釋放需要等到事務(wù)正確的結(jié)束,他占用的時(shí)間長短由事務(wù)大小決定
4. Latch 是非入隊(duì)的,而 Lock 是入隊(duì)的
5. Latch 不存在死鎖,而 Lock 中存在(死鎖在 Oracle 中是非常少見的)
看看下面這個(gè)例子,你會(huì)感覺到 Latch 的存在
SQL CREATE TABLE MYTEST AS SELECT OBJECT_NAME FROM USER_OBJECTS WHERE ROWNUM = 4;
Table created
SQL SET TIMING ON
SQL
DECLARE lv_name VARCHAR2(25) :=
BEGIN
FOR i IN 1..100000 LOOP
SELECT OBJECT_NAME INTO lv_name FROM MYTEST WHERE ROWNUM = 1;
END LOOP;
END;
/
PL/SQL procedure successfully completed
Executed in 3.359 seconds
這個(gè)進(jìn)程不斷的訪問表上的同一個(gè)數(shù)據(jù)塊,他先會(huì)物理讀取數(shù)據(jù)塊到數(shù)據(jù)緩沖區(qū),然后在內(nèi)存中不斷的獲取這個(gè)塊的 latch,現(xiàn)在只有單個(gè)進(jìn)程,運(yùn) 行的還好,10 萬次用了 3 秒多,但當(dāng)我拉出 4 個(gè)窗口同時(shí)并發(fā)的運(yùn)行這個(gè)語句時(shí),問題就出現(xiàn)了,多個(gè)進(jìn)程 PIN 同一個(gè)數(shù)據(jù)塊,每個(gè)大概花了 15 秒,并且看到 他們一個(gè)一個(gè)的結(jié)束,到最后只剩一個(gè)時(shí)一閃就過去了,因?yàn)闆]人和他搶了,這個(gè)實(shí)驗(yàn)展現(xiàn)了 Latch 競(jìng)爭的現(xiàn)象,對(duì)于 9I 提出的查詢可以共享 Latch 在此 我表示了質(zhì)疑。
產(chǎn)生 Latch 的原因主要是:
1、太多的會(huì)話訪問相同的數(shù)據(jù)塊導(dǎo)致熱塊的產(chǎn)生
2、共享池有太多的 sql 語句需要軟解析,沒有使用綁定變量
現(xiàn)在來看看進(jìn)程獲取 Latch 的詳細(xì)過程,任何時(shí)候,只有一個(gè)進(jìn)程可以訪問內(nèi)存中的某一個(gè)塊 (9I 提出的 Latch 共享我不想考慮),如果進(jìn)程 因?yàn)閯e的進(jìn)程正占用塊而無法獲得 Latch 時(shí),他會(huì)對(duì) CPU 進(jìn)行一次 spin(旋轉(zhuǎn)),時(shí)間非常的短暫,spin 過后繼續(xù)獲取,不成功仍然 spin,直到 spin 次數(shù)到達(dá)閥值限制(這個(gè)由隱含參數(shù)_spin_count 指定),此時(shí)進(jìn)程會(huì)停止 spin, 進(jìn)行短期的休眠,休眠過后會(huì)繼續(xù)剛才的動(dòng)作,直到獲取 塊上的 Latch 為止。進(jìn)程休眠的時(shí)間也是存在算法的,他會(huì)隨著 spin 次數(shù)而遞增,以厘秒為單位,如 1,1,2,2,4,4,8,8,。。。休眠的閥值 限制由隱含參數(shù)_max_exponential_sleep 控制,默認(rèn)是 2 秒,如果當(dāng)前進(jìn)程已經(jīng)占用了別的 Latch,則他的休眠時(shí)間不會(huì)太長(過長會(huì) 引起別的進(jìn)程的 Latch 等待),此時(shí)的休眠最大時(shí)間有隱含參數(shù)_max_sleep_holding_latch 決定,默認(rèn)是 4 厘秒。這種時(shí)間限制的休 眠又稱為短期等待,另外一種情況是長期等待鎖存器(Latch Wait Posting),此時(shí)等待進(jìn)程請(qǐng)求 Latch 不成功,進(jìn)入休眠,他會(huì)向鎖存器等待鏈表(Latch Wait List) 壓入一條信號(hào),表示獲取 Latch 的請(qǐng)求,當(dāng)占用進(jìn)程釋放 Latch 時(shí)會(huì)檢查 Latch Wait List,向請(qǐng)求的進(jìn)程傳遞一個(gè)信號(hào),激活休眠的進(jìn)程。Latch Wait List 是在 SGA 區(qū)維護(hù)的一個(gè)進(jìn)程列表,他也需要 Latch 來保證其正常運(yùn)行,默認(rèn)情況下 share pool latch 和 library cache latch 是采用這個(gè)機(jī)制,如果將隱含參數(shù)_latch_wait_posting 設(shè)置為 2,則所有 Latch 都采用這種等待方式,使用這種方式能夠比較 精確的喚醒某個(gè)等待的進(jìn)程,但維護(hù) Latch Wait List 需要系統(tǒng)資源,并且對(duì) Latch Wait List 上 Latch 的競(jìng)爭也可能出現(xiàn)瓶頸。
如果一個(gè)進(jìn)程請(qǐng)求,旋轉(zhuǎn),休眠 Latch 用了很長時(shí)間,他會(huì)通知 PMON 進(jìn)程,查看 Latch 的占用進(jìn)程是否已經(jīng)意外終止或死亡,如果是則 PMON 會(huì)清除釋放占用的 Latch 資源。
現(xiàn)在大家可以明白,對(duì) Latch 獲取的流程了,請(qǐng)求 -SPIN- 休眠 - 請(qǐng)求 -SPIN- 休眠。。。占用,這里有人會(huì)問為什么要 SPIN,為什么 不直接休眠等待? 這里要明白休眠意味著什么,他意味著暫時(shí)的放棄 CPU,進(jìn)行上下文切換(context switch),這樣 CPU 要保存當(dāng)前進(jìn)程運(yùn)行時(shí)的一些狀態(tài)信息,比如堆棧,信號(hào)量等數(shù)據(jù)結(jié)構(gòu),然后引入后續(xù)進(jìn)程的狀態(tài)信息,處理完后再切換回原來的進(jìn)程 狀態(tài),這個(gè)過程如果頻繁的發(fā)生在一個(gè)高事務(wù),高并發(fā)進(jìn)程的處理系統(tǒng)里面,將是個(gè)很昂貴的資源消耗,所以他選擇了 spin,讓進(jìn)程繼續(xù)占有 CPU,運(yùn)行一些 空指令,之后繼續(xù)請(qǐng)求,繼續(xù) spin,直到達(dá)到_spin_count 值,這時(shí)會(huì)放棄 CPU,進(jìn)行短暫的休眠,再繼續(xù)剛才的動(dòng)作,Oracle 軟件就是這 么設(shè)計(jì)的,世界大師們的杰作,自然有他的道理,我就不在這上面再費(fèi)文字了。
系統(tǒng)發(fā)生關(guān)于 Latch 的等待是沒發(fā)避免的,因?yàn)檫@是 Oracle 的運(yùn)作機(jī)制,當(dāng)你看到很高的 Latch get 時(shí)并不意味著你的系統(tǒng)需要調(diào)整,有時(shí)候很高的 get 值背后只有很短的等待時(shí)間,我們調(diào)整的對(duì)象應(yīng)該以消耗的時(shí)間來圈定,而不是看到一個(gè)很高的獲取次 數(shù)值,當(dāng)然,獲取值異常的高出別的等待時(shí)間幾十萬倍時(shí)我們還是要關(guān)心的,Oracle 關(guān)于 Latch 的等待非常繁多,主要的包括 share pool,library cache,cache buffer chains,buffer busy wait,每一個(gè)的調(diào)整幾乎都可以寫幾頁紙,以后慢慢完成吧。
“Latch 和 Lock 的區(qū)別是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編將為大家輸出更多高質(zhì)量的實(shí)用文章!