天天看點

記一次區域DB突發變慢的SQL優化博弈

作者介紹

黃浩,現任職于中國惠普,從業十年,始終專注于sql。十年一劍,十年磨砺。3年通信行業,寫就近3萬條sql;5年制造行業,遨遊在etl的浪潮;2年性能優化,厚積薄發自成一家。

謹以該優化方案,紀念裡約奧運會中國女排4強賽戰勝巴西女排。

2016年8月17日,這本是一個平常的日子,如果硬是要與其他重要事件關聯在一起,那就是裡約奧運會了。或許是08北京奧運的瘋狂激奮嚴重透支了國人的奧運熱情,而産生了審美疲勞;也或許是在經過幾代人的奮發圖強,國人不再需要奧運金牌數量來證明自我,進而看淡了奧運賽場的劍拔弩張人喊馬嘶。而與我而言,是由于工作、家庭的緣故,無暇奧運。

中午小憩後,将醒未醒中打開電腦,一封未讀郵件讓我瞬間驚醒睡意全無:

記一次區域DB突發變慢的SQL優化博弈

從郵件内容看,透露了如下幾個資訊:

是突然變慢:也就是說在此之前是沒有性能問題的,性能問題是突然性的;

代碼沒有改動:也就是說本次性能變慢并非代碼變更引起;

區域慢,中心不慢:也就是說同樣的sql,在不同的db伺服器上性能表現不一樣。

我首先想到的是執行計劃走偏導緻的,因為第一點和第二點很符合執行計劃走偏導緻性能問題的表象。于是,我找到開發人員拿到了sql,sql如下:

記一次區域DB突發變慢的SQL優化博弈

通過sql text,我找到了sqlid,從ash獲得的資訊如下:

記一次區域DB突發變慢的SQL優化博弈

從ash中我們發現:執行計劃很穩定,并沒有發生“走偏”的異象。

難道是資料量發生了變化,導緻了性能的突然變慢?

正當我計劃咨詢相關人員的時候,espace彈出了消息,是多人讨論組,裡面的人員名單中有開發人員、se及性能測試人員。經過一番你來我往的讨論後,資訊歸納如下:

這是個查詢基礎資料的sql,資料量并沒有發生變化;

由于是基礎資料,原始資料都是存放在中心庫,各個區域庫是通過ogg同步,是以,中心庫和個區域庫的資料量是一樣的;

經确認,所有的區域庫都變慢了,而中心庫則很好很快;

在變慢之前,沒有做任何的代碼變更;

由于一線業務對首頁加載突然變慢很不适應,影響面非常廣,是以勒令務必在當天予以解決;

同樣的代碼,同樣的表,同樣的資料量,為何中心和區域性能相差這麼大?是以,se要求在不修改代碼的基礎上解決該問題,很明顯,他認為這不是代碼的問題。

在上述6條資訊中,第5條資訊是最要命的,我瞄了下螢幕右下方,發現當時已是14:26,離下班隻有3個半小時。而至于第6條的要求,我心裡面已經有了解決方案的腹稿。

在排除了執行計劃走偏、資料量變化的因素後,我把目光瞄準了“中心快,區域慢”這一現象。于是我決定對比下中心和區域的執行計劃,看是否一緻?

區域執行計劃:

記一次區域DB突發變慢的SQL優化博弈

中心執行計劃:

記一次區域DB突發變慢的SQL優化博弈

果真,兩個執行計劃有明顯的偏差:

記一次區域DB突發變慢的SQL優化博弈

而在差異中,最紮眼的莫過于執行計劃的第20行,區域環境是unoin all,中心庫是union all pushed predicate。即中心庫對view做了謂詞推入,而區域庫則沒有,而這個視圖就是臭名昭著的該死的bas_project_all_v。

由于sql傳回的結果集很少,一般都是在50條以内,是以對該視圖進行pushed predicate是最優方案。從執行計劃中的cost中也可以看出,中心庫在view上的cost消耗為225,而區域庫的消耗竟達到了15322,相差兩個資料量級,套用對中國足球的評語“想不輸都難”,區域庫“想不慢都難”呀。

區域庫和中心庫執行計劃的差異是我想要的結果,因為有了這個結果,才能實施我的方案:綁定執行計劃,即将中心庫的執行計劃綁定到區域庫。我将臨時方案與se溝通後,se同意先通過綁定執行計劃的方式解決一線業務的性能之需。于是我将sqlid及plan_hash_value發給dba,由dba通過sql_profile的方式将中心庫的執行計劃綁定到了區域。

至此,按照正常的劇情設計,接下來的畫面應該是這樣的:通過綁定執行計劃,區域的性能得到飛速提升,臨時方案不戰而屈人之兵,兵不血刃的完成了優化,開發人員、se、測試人員、一線業務人員都皆大歡喜。而接下來的就可以有充裕的時間來分析區域庫不進行謂詞推入的原因,進而從根本上解決性能問題。

但是,生活終究是沒有劇本的。

當dba通過sql_profile完成綁定後,測試人員則回報:還是不行,感覺更慢了……原來是4-5秒,現在出不來。什麼情況?劇情也太反轉了。dba懵了、se懵了、我也懵了:沒道理呀!!!!dba趕緊復原,我再次去到區域庫,當我看到執行計劃的時候,我和我的小夥伴驚呆了,執行計劃中明明顯示是綁定了執行計劃的:

記一次區域DB突發變慢的SQL優化博弈

但是,謂詞卻沒有被推入。綁定執行計劃的方案最終以失敗告終。經過這一番折騰,時針轉到了4點半的方向,仍然是套用評論中國足球的一句話“留給中國隊的時間不多了”。

又回到問題的本質,影響oracle執行計劃的是cost計算,而cost的計算基礎則是表的統計資訊、索引、資料分布等因素。因為區域的資料是通過ogg從中心庫同步過來的,是以資料分布應該是一緻的,否則就不是性能問題,而是更嚴重的功能問題了。我收集了該sql涉及到的所有表對象,通過對比兩套環境,發現區域的統計資訊和中心基本上是一緻的;而索引也是一緻的。為了確定萬一,dba手工對這些表對象進行了一次統計資訊收集。而oracle依舊無動于衷,固執的抛棄了“謂詞推入”,即便是在sql中加上/*+ push_pred(p)*/hint。

情況變得越來越複雜,越來越糟糕,越來越不可控。

就在百思不得其解,一籌莫展之際,dba發來了一封郵件,内容如下:

記一次區域DB突發變慢的SQL優化博弈

意思是說:造成中心和區域執行計劃不一緻的原因是oracle的版本不一緻,針對視圖這種場景,中心庫的版本高,支援謂詞推入;而區域庫的版本低,不支援謂詞推入。

這封郵件并沒有解決問題,但是卻價值千金,因為它證明了:在區域庫現有版本的基礎上,很難通過背景技術(比如綁定執行計劃)來完成優化。

se也無奈的接受了db的建議:從sql上進行優化。而此時,時針又順時針方向移動了30°,也就是說我必須得在半小時内完成sql優化。

記一次區域DB突發變慢的SQL優化博弈
記一次區域DB突發變慢的SQL優化博弈

而這個sql就是“使用者配置項目清單”的代碼呀:

記一次區域DB突發變慢的SQL優化博弈

我立馬找到上次優化的sql,一對比,果然99%的吻合。于是我沿用上次優化後的sql,重新改寫了該sql:

記一次區域DB突發變慢的SQL優化博弈
記一次區域DB突發變慢的SQL優化博弈
記一次區域DB突發變慢的SQL優化博弈
記一次區域DB突發變慢的SQL優化博弈

一執行,飛快秒出。

客戶虐我千百遍,我待客戶如初戀。我趕緊将這個sql送出給了se,滿以為可以定氣收工了。但是se看了sql後,說了一句:這個sql改動太大了,存在很大的風險。言下之意就是否決了這個優化方案。而此時,時間已經走到了17:45,距離下班隻剩下15分鐘,此刻,我能感覺到手心都滲出汗來了。15分鐘,已經沒有時間再與se争論方案的可靠性(上次的優化方案已經實施了一段時間,足以證明方案的正确性),我必須要在15分鐘内找出一個更保險的方案。

還得回到功能邏輯上。這個sql是根據user_id擷取所屬的project_number清單,然後再通過視圖bas_project_all_v中比對某些屬性,而顯然單個user_id的project_number的數是非常少的。此時,我靈機一動,心裡在想:是否可以先通過with子查詢擷取該使用者的所有project_number清單,然後在與視圖bas_project_all_v關聯呢?

死馬當成活馬醫。我來不及多想,就改寫了這個sql:

記一次區域DB突發變慢的SQL優化博弈
記一次區域DB突發變慢的SQL優化博弈

再次執行,1s。再次送出給se,由于隻是将普通子查詢改成了with子查詢,se認為風險可控。此時時間已是17:58,離18:00隻剩2分鐘。我長舒了口氣,望窗外,路面濕漉漉的,低窪處還明顯有積水;而殘陽如血,雲淡天高。剛過去的一場暴風雨沖刷了炎炎烈日,帶來了秋後的絲絲涼意。

在班車上浏覽起新聞來,立馬被頭條吸引住了:中國女排3:2戰勝了巴西隊。天呐,這無疑是一個奇迹呀,大寫的奇迹呀。巴西女排,兩屆奧運冠軍,又坐擁東道主之利,可謂是占盡了天時地利人和。賽前也了解過,中國女排無論是技戰術還是大戰經驗,都不及巴西隊,而就是這些被低看的中國姑娘們,用女排魂拼出了一個奇迹,而就在中國女排姑娘們在賽場上“像老虎一樣撕咬”巴西女排、“打哭巴西小球迷”時,我也在拼力在為首頁加載的性能問題不折不饒。

雖然兩者的價值成果不可同日而語,但是其内在的精神是一緻的:不到最後不放棄的執着,心無旁骛心力齊的專注,排除萬難大無畏的拼搏,不到樓蘭死不休的勇氣;有的時候,的确需要一股子狠勁,一股子對自己的狠勁,這樣才能激發自己的潛能,去完成不可能完成的任務。

原文釋出時間為:2017-01-10

本文來自雲栖社群合作夥伴dbaplus