SQL優(yōu)化:利用 batch join 優(yōu)化分布式中的 rescan 性能問(wèn)題

在分布式數(shù)據(jù)庫(kù)中辈赋,關(guān)聯(lián)查詢不可避免地對(duì)分布在不同節(jié)點(diǎn)的表、分區(qū)進(jìn)行跨節(jié)點(diǎn)的關(guān)聯(lián)操作,數(shù)據(jù)在不同節(jié)點(diǎn)間的分發(fā)方式對(duì)關(guān)聯(lián)查詢的性能至關(guān)重要。在 NLJ(nested-loop join) 和 SPF(subplan filter) 中设褐,需要針對(duì)驅(qū)動(dòng)表中的每一行重新掃描被驅(qū)動(dòng)表中的數(shù)據(jù),如果被驅(qū)動(dòng)表是分區(qū)表且分布在不同的機(jī)器上, 在分布式重新掃描(rescan)的過(guò)程中會(huì)包括資源釋放泣刹、調(diào)度重啟等過(guò)程助析,這些操作常常伴隨著消息等待、同步以及網(wǎng)絡(luò)傳輸操作, 影響執(zhí)行效率椅您。

  • 分布式交互包括釋放上一次子協(xié)調(diào)節(jié)點(diǎn)執(zhí)行資源的控制消息外冀、調(diào)度子協(xié)調(diào)節(jié)點(diǎn)的控制消息等,這些若干控制消息的 RPC 交互會(huì)帶來(lái)額外的開(kāi)銷(xiāo)
  • 調(diào)度重啟的代價(jià)高是由于 Nested Loop Join 被驅(qū)動(dòng)表可能是分布式復(fù)雜子計(jì)劃掀泳,需要重新建立子計(jì)劃調(diào)度關(guān)系锥惋,這個(gè)重新建立的過(guò)程會(huì)帶來(lái)調(diào)度的開(kāi)銷(xiāo)
  • 另外大量的網(wǎng)絡(luò)交互也會(huì)極大的增加響應(yīng)時(shí)間

下面通過(guò)一個(gè)案例分享在 OceanBase 中利用 batch join 優(yōu)化分布式中的 rescan 性能問(wèn)題。

問(wèn)題描述

這個(gè)問(wèn)題出現(xiàn)在一個(gè)測(cè)試環(huán)境的 4.2.1 BP3 版本中开伏,表 a 驅(qū)動(dòng)表 f 做 nested-loop join,a遭商、f 表不在同一個(gè) observer 并且都是非分區(qū)表固灵。驅(qū)動(dòng)表輸出結(jié)果5萬(wàn)行左右,被驅(qū)動(dòng)表 f 走高效索引劫流,最終結(jié)果輸出 11萬(wàn)行左右巫玻,這個(gè)SQL執(zhí)行耗時(shí)要 60秒:

select  a.ah,f.aj
from db1.t1 a
join db2.t2 f on a.ah=f.ah 
where a.sxrq>=date'2020-01-01' 
and aydm in (3029,6209,6210,6365,6366,6469,8179,8180,8271,8294,8789)
and ajxzdm='2'
and jafsmc like '%脫敏%';

在本案例中,對(duì)被驅(qū)動(dòng)表做了5萬(wàn)次rescan祠汇,產(chǎn)生了5萬(wàn)次 rpc 訪問(wèn)仍秤,網(wǎng)絡(luò)上兩個(gè) observer 之間一次 rtt 平均 0.8ms,因此非常慢可很。OceanBase 優(yōu)化器是支持 batch join 的诗力,會(huì)減少 rescan 次數(shù)提升效率,但這里似乎沒(méi)有我抠,下文基于此進(jìn)行解析苇本。

分析過(guò)程

1. 分析 gv$ob_sql_audit

主要目的是獲取兩個(gè)信息:trace_id袜茧、執(zhí)行耗時(shí) 61秒

+----------------------------+----------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+--------------+--------------+
| usec_to_time(request_time) | svr_ip         | plan_type | query_sql                                                                                                                                                                                                                                  | trace_id                          | elapsed_time | execute_time |
+----------------------------+----------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+--------------+--------------+
| 2024-03-26 16:04:53.124344 | xxx            |         1 | select /*+ monitor */
a.ah
from db1.t1 a
join db2.t2 f on a.ah=f.ah 
where a.sxrq>=date'2020-01-01' 
and aydm in (3029,6209,6210,6365,6366,6469,8179,8180,8271,8294,8789)
and ajxzdm='2'
and jafsmc like '%脫敏%';   | YB4289116C6E-000613F0D09FF63D-0-0 |     61845207 |     61782771 |
+----------------------------+----------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+--------------+--------------+
1 row in set (1.564 sec)
2. 分析執(zhí)行計(jì)劃

從執(zhí)行計(jì)劃來(lái)看,NESTED-LOOP JOIN 算子中被驅(qū)動(dòng)表走了非常高效的索引瓣窄,每次查詢只掃1行笛厦,要挑毛病只有驅(qū)動(dòng)表 A 沒(méi)走索引了、以及沒(méi)使用 batch join 了(use_batch=false):
3. 分析gv$sql_plan_monitor

執(zhí)行計(jì)劃看著沒(méi)問(wèn)題俺夕,這個(gè) SQL 不應(yīng)該這么慢裳凸,因此需要通過(guò) gv$sql_plan_monitor 看下真實(shí)的執(zhí)行情況,查詢命令如下:

SELECT op_id, op, output_rows, rescan, threads,
       close_time - open_time AS open_dt,
       last_row_eof_time - first_row_time AS row_dt,
       open_time, close_time, first_row_time, last_row_eof_time
FROM (
        SELECT plan_line_id AS op_id,
               concat(lpad(' ', max(plan_depth), ' '), plan_operation) AS op,  --算子名稱
               sum(output_rows) AS output_rows,  --算子輸出行數(shù)
               sum(STARTS) AS rescan, --算子被 rescan 的次數(shù)
               min(first_refresh_time) AS open_time,  --算子開(kāi)始(監(jiān)控)時(shí)間
               max(last_refresh_time) AS close_time,  --算子結(jié)束(監(jiān)控)時(shí)間
               min(first_change_time) AS first_row_time,  --算子吐出首行數(shù)據(jù)時(shí)間
               max(last_change_time) AS last_row_eof_time, --算子吐出最后一行數(shù)據(jù)時(shí)間
               count(1) AS threads  --線程數(shù)量
        FROM gv$sql_plan_monitor
        WHERE trace_id = '替換成trace_id'
        GROUP BY plan_line_id, plan_operation, plan_depth
        ORDER BY plan_line_id
) a;

結(jié)果如下:

這里可以看出幾個(gè)信息:

  • 驅(qū)動(dòng)表輸出 49557 行劝贸,近5萬(wàn)行姨谷,等于被驅(qū)動(dòng)表 rescan 次數(shù),被驅(qū)動(dòng)表輸出 11萬(wàn)行左右悬荣;
  • 每個(gè)算子的耗時(shí)都是 61 秒菠秒,這是正常的,因?yàn)檫@里只做了 nested-loop join氯迂,過(guò)程是:
    • 驅(qū)動(dòng)表取一行數(shù)據(jù)践叠,開(kāi)始計(jì)時(shí),這是1號(hào)算子的開(kāi)始吐行時(shí)間
    • 到被驅(qū)動(dòng)表進(jìn)行查詢嚼蚀,開(kāi)始計(jì)時(shí)禁灼,這是2號(hào)算子的開(kāi)始吐行時(shí)間
    • 直到循環(huán)結(jié)束,1轿曙、2號(hào)算子的最后吐行時(shí)間是一樣的
      因此并不能簡(jiǎn)單的認(rèn)為1號(hào)算子即驅(qū)動(dòng)表就耗時(shí)了 61 秒弄捕,這是不對(duì)的。需要從 5萬(wàn)次 rescan 入手导帝。
4. 確認(rèn) rpc_count 和表位置

通過(guò) GV$CDB_OB_TABLE_LOCATIONS 確認(rèn)了 db1.t1守谓、db2.t2 兩張表不在一個(gè) unit 上,因此 join 時(shí)需要跨 observer您单,通過(guò) gv$ob_sql_audit 確認(rèn)這個(gè)SQL執(zhí)行時(shí)產(chǎn)生了49557 次 rpc(rpc_count=49557)斋荞。
對(duì)應(yīng)的執(zhí)行計(jì)劃中,join 算子 use_batch=false虐秦,同樣說(shuō)明被驅(qū)動(dòng)表 f 進(jìn)行了 49557 次 rescan平酿。

5. 開(kāi)啟 batch join

要減少被驅(qū)動(dòng)表的 rescan 次數(shù),需要讓 batch join 生效悦陋, 這由租戶的隱藏變量 _NLJ_BATCHING_ENABLED 來(lái)控制蜈彼, 通過(guò) CDB_OB_SYS_VARIABLES 可以查詢隱藏變量的設(shè)置情況:

select TENANT_ID,NAME,VALUE,INFO,DEFAULT_VALUE from CDB_OB_SYS_VARIABLES where name='_NLJ_BATCHING_ENABLED';

結(jié)果如下,發(fā)現(xiàn) batch join 默認(rèn)關(guān)閉了:

將 batch join 開(kāi)啟:SET global _NLJ_BATCHING_ENABLED=true;俺驶,然后再執(zhí)行SQL幸逆,耗時(shí)從61秒下降到 2.8秒,執(zhí)行計(jì)劃中 use_batch=true。

總結(jié)

本案例中秉颗,SQL執(zhí)行慢的原因是被驅(qū)動(dòng)表與驅(qū)動(dòng)表不在一個(gè) observer 上痢毒,當(dāng)前使用版本 4.2.1 BP3,_NLJ_BATCHING_ENABLED 默認(rèn)關(guān)閉蚕甥,因此沒(méi)有使用 DAS Group rescan 優(yōu)化哪替,即沒(méi)有使用 batch join,導(dǎo)致被驅(qū)動(dòng)表 rescan 次數(shù)太多菇怀,并且是跨 observer rescan凭舶,所以非常慢。

本案例中有幾個(gè)注意事項(xiàng):

  1. gv$sql_plan_monitor 中的 rescan 不能代表真實(shí)的 rescan 次數(shù)爱沟,應(yīng)該恒等于驅(qū)動(dòng)表的輸出行數(shù)帅霜,即使優(yōu)化器進(jìn)行了 DAS Group rescan 優(yōu)化
  2. gv$ob_sql_audit 中 rpc_count 字段可以用來(lái)確認(rèn) NLJ 算子中被驅(qū)動(dòng)表的 rescan 次數(shù)
  3. gv$sql_plan_monitor 中的查詢出來(lái)的算子輸出行的總時(shí)間結(jié)果有可能多個(gè)算子一樣,這個(gè)要看具體算子的執(zhí)行邏輯來(lái)解讀
  4. batch join 并不像官方文檔說(shuō)的一樣總是默認(rèn)開(kāi)啟的呼伸,后來(lái)在 release note 中找到了原因:因?yàn)橐恍?bug 在V4.2.1 BP2 Hotfix1 版本中身冀,默認(rèn)關(guān)閉了該優(yōu)化功能,后面又在V4.2.1 BP5 默認(rèn)打開(kāi)該優(yōu)化開(kāi)關(guān)括享。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搂根,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铃辖,更是在濱河造成了極大的恐慌剩愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仁卷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡犬第,警方通過(guò)查閱死者的電腦和手機(jī)锦积,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)歉嗓,“玉大人充包,你說(shuō)我怎么就攤上這事∫4唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵淆储,是天一觀的道長(zhǎng)冠场。 經(jīng)常有香客問(wèn)我,道長(zhǎng)本砰,這世上最難降的妖魔是什么碴裙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上舔株,老公的妹妹穿的比我還像新娘莺琳。我一直安慰自己,他們只是感情好载慈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布惭等。 她就那樣靜靜地躺著,像睡著了一般办铡。 火紅的嫁衣襯著肌膚如雪辞做。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天寡具,我揣著相機(jī)與錄音秤茅,去河邊找鬼。 笑死童叠,一個(gè)胖子當(dāng)著我的面吹牛框喳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厦坛,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼五垮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了粪般?” 一聲冷哼從身側(cè)響起拼余,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亩歹,沒(méi)想到半個(gè)月后匙监,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡小作,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年亭姥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顾稀。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡达罗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出静秆,到底是詐尸還是另有隱情粮揉,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布抚笔,位于F島的核電站扶认,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏殊橙。R本人自食惡果不足惜辐宾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一狱从、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叠纹,春花似錦季研、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冒窍,卻和暖如春递沪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背综液。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工款慨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谬莹。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓檩奠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親附帽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子埠戳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容