Oracle並行基礎二

Oracle並行基礎(連載二)

作者:沃趣科技高級數據庫技術專家 魏興華



消費者生產者模型的限制

根據上面的介紹,你已經知道了,一個並行操作內一般會具有兩組PX slave進程,一組爲生產者,一組爲消費者。生產者通過table queue發送數據,消費者通過table queue接收數據。而且對於消費者和生產者模型,有一個很大的限制是:一組DFO單元最多只能有兩組PX slave進程,之所以有這個限制,一方面可能是Oracle公司爲了保持並行代碼的簡潔性,一方面由於每個PX slave進程之間和每個PX slave與QC之間都要維持一個通信通道(table queue)用於傳遞消息和數據,如果允許的PX slave有太多組,可能會導致通信通道指數級增長。例如一個DOP爲5的並行操作,PX slave之間需要的通道數爲55,PX slave與QC之間的通道數爲25,共需要(5+2)5=35個通道。可想而知,如果Oracle允許一個並行操作內有3組PX slave,需要維持的連接數有多少,我們假設當前服務器共運行了50個並行,那麼三組PX slave進程產生的通道數爲5050*50=125000個,還不包括PX slave與QC之間的通道,嚇尿了不?

parallel_execution_message_size

如果進程之間傳遞消息的通道數多但不佔用數據庫資源可能也並不是什麼大的問題,但是事實不是這樣的,進程之間傳遞消息的通道的內存佔用大小是由參數parallel_execution_message_size控制的,在11GR2版本這個參數的值爲16K,在以前的各個版本這個參數的值可能大小並不一樣(每個版本都有增大的趨勢),在非RAC環境下,每個通道的大小最大可以爲3parallel_execution_message_size,在RAC環境下,每個通道的大小最大可以爲4parallel_execution_message_size。
例如一個DOP爲20的查詢,非rac環境下通道所佔用的內存最大可能爲:
PX進程的通道內存+QC、PX進程之間的通道內存=202016K3+22016K3=21120K,接近21M的內存。
通道的內存默認是在large pool中分配,如果沒有配置large pool則在shared pool中分配。
計算通道內存的公式:
單節點
(NN+2N)316k
RAC節點
(NN+2N)416k

hash join buffered

其實不是hash join的缺陷。
我們已經介紹過生產者消費者模型,它有一個很大“缺陷”是,一個並行操作內,最多只能有2組PX slave,2組PX slave通過table queue來傳遞消息和交互數據,因此在一組SLAVE在讀table queue的時候,不能同時去寫另一個table queue。是不是不太好理解?
我們通過一個例子來進行描述:

select /*+ parallel(6) pq_distribute(b hash hash)*/ * from hash_t3 a ,hash_t1 b where a.id=b.id;


  這個例子裏我通過hint pq_distribute(b hash hash)強行讓數據以hash方式進行分發,關注行源ID爲3的操作,出現很陌生的一個操作:hash join buffered,不要被這個buffered名字所迷惑,它代表着數據暫時不能向上流動,必須先暫時存放在這裏,語句的執行順序是這樣的:

  • 首先紅色的生產者PX slave掃描hash_t3表,並對掃描的記錄按照HASH分發方式把相關記錄寫入table queue TQ10000

  • 藍色的消費者PX slave從table queue TQ10000接收數據並構建hash table。

  • 上面操作結束後,紅色的生產者繼續掃描hash_t1表,並對掃描的記錄按照HASH分發方式寫入table queue TQ10001

  • 藍色的消費者PX slave從table queue TQ10001接收數據,並與上面的HASH TABLE做探測,但是結果並不能寫入table queue TQ10002,而是先暫時緩存起來(hash join buffered的由來)

  • 等HASH分發完成之後(也就是這兩組PX slave不活躍以後),然後由一組PX slave把結果集通過table queue TQ10002發送給QC。

爲什麼要這樣?貌似是沒有道理的。
這就是因爲hash分發要求對hash join的右邊也要進行分發,分發操作涉及了2組PX slave進程,一組負責掃描,一組負責接收數據,也就是一組PX slave把掃描的數據寫入table queue,一組負責從table queue讀取數據,這個時候不能 再進行數據的分發操作,因爲join的結果集不能寫入另一個table queue TQ10002。
如果結果集較大的話,這個可能在一定程度上會導致消耗很多臨時表空間,導致大量的磁盤讀寫IO,進而引起性能降低。
如果確實產生了這種情況,可以通過改用broadcast分發來避免出現這種情況,因爲broadcast分發對於hash join的右邊並不需要進行分發

select /*+ parallel(6) pq_distribute(b broadcast none)*/ * from hash_t3 a ,hash_t1 b where a.id=b.id;


例如改成broadcast後,hash join buffered操作已經消失了。

布隆過濾

我們有必要介紹一下布隆過濾,它在11GR2之後版本的並行裏有非常大的作用。bloom filter並非Oracle的發明,bloom filter技術出現的時候Oracle軟件還未誕生,它在1970年由Burton H.Bloom開發出來,布隆過濾到什麼?
布隆過濾或者說布隆過濾器,是一種數據結構,它能夠快速的判斷一個數據是否屬於一個集合,hash join本身是非常消耗資源的,也是非常慢的,布隆過濾比hash join快很多。

關於布隆過濾的詳細介紹請參照:http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html


布隆過濾器基於一個有M位的數組,例如上圖數組的大小有18位,初始化的時候全部的值都爲0,如果要理解布隆過濾是如何工作的,必須要知道在什麼情況下,這些標誌位需要置爲1,上圖中{X,Y,Z}代表着一個集合,這個集合有3個值(元素),仔細觀察每一個值都延伸出了三個線,在這裏代表着每一個值都經過3個HASH函數計算,計算出來的值的範圍是從0-17(數組的長度),例如,X經過3次HASH函數計算,值分別爲:1,3,13,然後對應的標誌位被置爲1,Y,Z同理把相應的標誌位置爲1。經過一番HASH計算,{X,Y,Z}集合的所有元素都已經經過了HASH計算,對應的標誌位也都置爲了1,然後我們再探測另一個集合,這裏另一個集合的元素爲W,W同樣需要經過相同的3個HASH函數計算,並且檢測對應的位置是否爲1,如果對應的位置都爲一,那麼W可能(僅僅是可能)屬於這個集合,如果有任何的位置不爲1,那麼這個W一定不屬於這個集合。由於布隆過濾並不對值進行精確的匹配(而HASH JOIN是需要精確匹配的),因此可能會有一些不該屬於集合的值穿越了布隆過濾器。

布隆過濾器有如下特點:

  • 構建布隆過濾數組要求的內存非常小,經常可以完全放入在CPU的cache中。當然布隆過濾的數組越大,布隆過濾誤判的可能性也就越小。

  • 由於不需要精確匹配,因此布隆過濾的速度非常的快,但是有一些不該出現的值可能會穿越布隆過濾器。


PX Deq Credit: send blkd 與PX Deq Credit: need buffer

布隆過濾有啥用呢?也許你是一位有着豐富經驗的老DBA,那麼你對PX Deq Credit: send blkd 、PX Deq Credit: need buffer等待事件也許就比較熟悉。經過上面的介紹,我們已經具備了很多的知識,table queue,生產者消費者模型等等,一組消費者PX slave寫入table queue,另一組通過讀取table queue來獲取數據,完成進程間數據的傳遞,但是一定會出現一種情況,當一組生產者PX slave在往table queue中寫入數據的時候,發現table que中的內存已經滿了,沒有剩餘內存可以寫了,這種情況大部分時候都意味着消費者PX slave從table queue中消費數據過慢,過慢最大可能原因是由於消費者不得不把table queue中讀取到的數據溢出到磁盤,從內存讀取數據寫入磁盤是個很慢的操作,因此在這種情況下,就會遭遇PX Deq Credit: send blkd 、PX Deq Credit: need buffer等待,如何優化?這種情況下,布隆過濾就發揮了作用。
如果優化器認爲表X返回1000條記錄,表Y需要掃描一億條記錄,但是經過HASH JOIN後,有90%都不需要返回,這種情況下使用布隆過濾在進行HASH分發前預HASH JON。這樣經過布隆過濾器,有大量的記錄就被布隆過濾器所淘汰,最後HASH JOIN右邊的結果集就變得非常小,也就讓HASH 分發的數據量變得非常的小,大大減少了出現PX Deq Credit: send blkd 、PX Deq Credit: need buffer的概率。如果不使用布隆過濾,進程不得不傳遞大量的數據給另一組進程,增加了內存,CPU,增加了兩組進程的進程間競爭。
不要期待布隆過濾是完美的,他能消除掉大部分的行,但是不是 所有的行,因此有一些不需要的數據會穿過布隆過濾器達到第二組進程。

並行度降級

無論你使用的是手工指定DOP,還是使用11G的AUTO DOP,運行時的DOP都有可能與你預期的不一樣:可能被降級。可能會有很多種原因導致並行被降低,例如,當前系統中可用的並行進程已經不能滿足需要的DOP,或者你已經使用了Oracle的資源管理器對並行度做了限制,等等。
監控並行度降低的最好工具是oracle 12.1版本的SQL MONITORING,例如:


如上圖,在【一般信息】部分,將你的鼠標放在Execution Plan部分的藍色小人上,將會出現一些並行度的信息,例如上圖中,運行時間的DOP爲4,實際請求的並行服務進程爲10,實際分配的並行服務進程爲4,並行度被降低的百分比爲60%。
爲了找出語句被降級的理由,你可以點擊【計劃統計信息】部分,PX COORDINATOR行源的其他列,如下圖,用紅色框標記:
點擊後出現:

以下是被降級的一些代碼說明:
350 DOP downgrade due to adaptive DOP
351 DOP downgrade due to resource manager max DOP
352 DOP downgrade due to insufficient number of processes
353 DOP downgrade because slaves failed to join
我這裏的情況是,由於系統可以使用的並行進程不足導致分配並行資源失敗。
如果你不方便使用EMCC,也可以通過視圖觀察到並行度降級的情況,但是被降級的理由,暫時還沒有視圖反應(或者我還不知道,如果你知道請告訴我)

DEGREE 列爲實際的並行度,REQ_DEGREE 爲請求的並行度。
有一些手段可以避免並行度降級,例如如果使用的是ORACLE 11G版本,可以使用自動並行管理功能,然後結合在語句級指定並行度。因爲自動並行度功能一單被打開,並行語句排隊功能將被啓用,如果語句運行時發現沒有足夠的可用並行進程,那麼會排隊等待,直到有滿足目標的可用並行進程。

多個DFO 單元

一些命令可以有多個DFO單元,因爲每個DFO單元最多可以使用2個PX slaves set,如果一個命令有多個DFO單元,那麼它就可以使用超過2個PX slaves set,可以在執行計劃裏看到是否使用了多個DFO單元:
select count() from (select /+ parallel(a 4) /count() from hash_t1 a
union
select /+ parallel(b 4) / count(*) from hash_t2 b)


行ID爲6和12的行源兩處都有coordinator標識,這意味着這個命令使用了2個DFO單元。

通過SQL MONITORING也可以看到這個命令具有了2個並行組,理論上每個DFO單元之間可以同時進行並行操作,但是我們這個例子裏,兩個DFO單元之間的執行順序是,先執行DFO單元1,再執行DFO單元2,可以通過【時間表】列看到,第一個DFO單元先活躍,等結束後,第二個DFO單元開始活躍。
從上圖還可以看出,DFO單元2複用了DFO單元1的並行進程,沒有重新產生新的並行進程,從並行進程編號上可以看出這一點。SQL MONTIRONG是不是超級好用?

v$pq_sesstat視圖


通過查詢v$pq_sesstat視圖,可以知道語句運行時的DFO單元的數量(DFO Trees),並行集的個數(Slave Sets ),服務進程的個數(Server Threads),執行所採用的並行度(DOP)。如下:

寫到這裏文章已經有點長了,對於12C的新特性還少有涉及,對於並行執行傾斜的內容也還未涉及,對於布隆過濾的傳遞和高級知識也未涉及。對於這些內容,我會在下一篇進行介紹。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章