背景簡介: Oracle版本:11.2.0.4 OS 版本:OEL5.8 在一次Oracle的Dataguard正常switchover過程中,遇到了一個極其詭異的問題,一條主業務的SQL語句在新主庫的執行時間由之前的毫秒級別完成變成了20-60秒不等,為避免高峰業務超時必須儘快進行優化,否則只能走 ...
背景簡介:
Oracle版本:11.2.0.4 OS 版本:OEL5.8
在一次Oracle的Dataguard正常switchover過程中,遇到了一個極其詭異的問題,一條主業務的SQL語句在新主庫的執行時間由之前的毫秒級別完成變成了20-60秒不等,為避免高峰業務超時必須儘快進行優化,否則只能走回退方案。
優化過程:
其實這個語句在之前將備庫切換為snapshot備庫做測試時表現是非常良好的,但是切換之後立馬出了問題。在備庫實際執行後獲取到的執行計劃與在主庫一模一樣,如下:
獲取執行計劃的語句如下:(語句出自ITPUB大神版主lfree)
select *
from
table(dbms_xplan.display_cursor(NVL('&1',NULL),
NULL,
'ALL ALLSTATS LAST PEEKED_BINDS cost partition -projection -outline &2'));
這裡的參數1和2全部設置為空即可,此語句可以查出當前會話中上一個執行過語句的真實執行計劃。
此SQL中不涉及視圖,所以這個執行計劃是非常好的,在主庫執行也是毫秒級別的,因此同樣的執行計劃在備庫卻非常慢就很值得思考了。
接下來我利用set autot工具得到了執行此SQL後的統計信息,發現存在大量物理讀。這裡就很搞笑了,真實執行計劃中不存在表掃描,所以出現這麼多的物理讀一定是回表操作特別多,那麼為什麼回表?顯然記憶體不夠。
於是我將SGA加大至80GB(比主庫還大20GB),重啟資料庫再查,問題依舊。
我依然堅信是緩存的問題,那麼必須要搞清為何數據未被緩存至記憶體,對Oracle資料庫來說大多有2個原因:
1、數據太多,記憶體太小。
2、不是熱點數據,被LRU刷出記憶體。
首先排除第二條,原主庫60G的SGA都可以,現在80G的SGA沒理由不可以。
此外註意到一個現象,v$sgainfo中的buffer pool在接近30GB時有一個很長時間的停頓,然後才慢慢增長至接近70G(剩餘部分屬於sharedpool等)。
於是突然想到NUMA的問題,果然:
numactl --hardware的運行結果:
這就尷尬了,在/etc/grub.conf的kernel一行後添加了numa=off,重啟伺服器後果然問題被解決。
事後查看資料庫日誌找到瞭如下信息:
.
因此可以確認是操作系統未關閉NUMA特性引起的(只設置資料庫禁用NUMA的隱含參數是無用的,Oracle在11GR2之後已經預設禁用NUMA,但只是資料庫級別)。
關於Oracle NUMA的相關信息,參考官網文檔:Oracle NUMA Usage Recommendation (文檔 ID 759565.1)
名詞解釋:
什麼是NUMA:
NUMA模式是一種分散式存儲器訪問方式,處理器可以同時訪問不同的存儲器地址,大幅度提高並行性。 NUMA模式下,處理器被劃分成多個"節點"(node), 每個節點被分配有的本地存儲器空間。 所有節點中的處理器都可以訪問全部的系統物理存儲器,但是訪問本節點內的存儲器所需要的時間,比訪問某些遠程節點內的存儲器所花的時間要少得多。
--OK,註意這幾個字:大幅提高並行性。Oracle資料庫絕大多數時候進程都是串列的,除非特意設置並行度,而SQL Server也只有超過cost閾值才會並行,因此資料庫伺服器應該禁用NUMA。
關於NUMA更加詳細的信息參考:
https://www.ibm.com/developerworks/cn/linux/l-numa/index.html
https://technet.microsoft.com/zh-cn/library/ms178144(v=sql.105).aspx
http://www.cnblogs.com/yubo/archive/2010/04/23/1718810.html