一般在混合型環境中,大表在進行全表掃描或者走並行的時候一般會出現direct path read等待事件,如果在OLTP或者純粹的DSS環境中,出現大量的direct path read直接路徑讀取,這樣就有問題了,尤其是一些流水線的批處理系統中,會導致大量的free buffer wait等(因為direct path reads會導致oracle執行object level checkpoint將所有目標對象的臟塊寫入磁盤,然后將這些塊從磁盤讀取到進程的PGA,如果有未提交的事務,還必須使用PGA構造讀一致性塊緩沖。所以parallel是把雙刃劍,用的不好,系統性能會很慢,尤其是在跑批系統中,增加了大量不必要的物理讀寫,要想跑的飛快,cpu利用起來,應用層的fork-join線程池設計極大的決定了系統的性能)。一般在OLTP中,都是事務型的sql,如果想sql執行效率,那么最好從內存當中讀取數據,直接從數據文件中讀取,后果可想而知了。這里就可能需要我們禁用direct path read。
在oracle 11.2之前,只要沒有設置_serial_direct_read為true,同時沒有指定並行執行,oracle會將HWM以下的塊讀入buffer cache。如果走了並行執行,意味着所有的表都會導致direct read,即使表不大也如此。
從11.2開始,oracle默認會自動決定要不要在非並行執行的時候繞過buffer cache並使用direct path read(為什么這是合適的呢,舉個例子,假設有張表有1億條數據,平均紀錄長度200,全表掃描意味着20G的buffer cache,而服務器本身可能只配置了64G,很明顯一張1億條記錄的表不太可能是所有記錄都經常要訪問的,但是其中的1/10經常訪問是可能的,此時如果這個表沒有分區顯然是不合理的)。同時,更重要的是,我們可以通過參數控制並行查詢的時候對某些表的掃描可以走buffer cache,而不是direct read。
oracle根據幾個參數決定全表掃描的時候是否走直接路徑讀,首先是_small_table_threshold隱含參數,它決定oracle認為的小表閾值(同時,讀取少於該值的parallel將使用buffer cache),每個環境和版本都可能不同,默認值約為默認值是db cache size的2%大小。如下:
_serial_direct_read值控制非並行執行的時候是否允許走直接讀。默認情況下,如果表大於_small_table_threshold*5,則全表掃描的時候自動會被調整為direct read,也就是buffer cache的1/10左右(這個算大、也不算大)。
這個值其實應該被啟用,這是對的,但是應該合理設置_small_table_threshold的閾值以最小化不必要的物理io。
可以通過兩種方式是禁用直接讀,如下:
SQL> alter system set event='10949 TRACE NAME CONTEXT FOREVER, level 1' scope=spfile; System altered SQL> alter session set "_serial_direct_read"=false; Session altered SQL> SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ 2 FROM SYS.x$ksppi x, SYS.x$ksppcv y 3 where x.indx = y.indx 4 AND (x.ksppinm = '_small_table_threshold' or 5 x.ksppinm = '_serial_direct_read'); NAME VALUE DESCRIB -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- _small_table_threshold 30338 lower threshold level of table size for direct reads _serial_direct_read FALSE enable direct read in serial SQL>
還有一個參數 _very_large_object_threshold 用於設定(MB單位)不使用direct path read方式的上限,這個參數需要結合10949事件共同發揮作用。10049和_very_large_object_threshold參數一起的時候,只要_very_large_object_threshold小於目標表大小*0.8或者buffer cache*5,就可以不走direct path read。所以,要想完全禁用非並行執行時的直接路徑讀,只要將_very_large_object_threshold設置的足夠大即可,不過不建議超過20%*buffer cache(否則要么是分區沒使用或者不合理)。
所以在並行和串行之間存在一個矛盾點,這個矛盾點只能通過高配置服務器比如256GB/128C+良好的表結構設計或者應用層面的分而治之來解決。
當然,我沒有仔細去測,最近太忙,沒有時間一一去驗證,后面會仔細驗證效果如何。
這給帖子寫的不錯,可以參考下http://www.itpub.net/thread-1815281-1-1.html
參考:http://oracleinaction.com/direct-reads-11g/