瞄一眼,帶你走進SparkSQL的世界

本文由  網易雲 發佈。html

 

做者:範欣欣(本篇文章僅限知乎內部分享,如需轉載,請取得做者贊成受權。)算法

最近想來,大數據相關技術與傳統型數據庫技術不少都是相互融合、互相借鑑的。傳統型數據庫強勢在於其久經考驗的SQL優化器經驗,弱勢在於分佈式領域的高可用性、容錯性、擴展性等,假以時日,讓其通過必定的改造,好比引入Paxos、raft等,強化本身在分佈式領域的能力,相信必定會在大數據系統中佔有一席之地。相反,大數據相關技術優點在於其天生的擴展性、可用性、容錯性等,但其SQL優化器經驗卻基本所有來自於傳統型數據庫,固然,針對列式存儲大數據SQL優化器會有必定的優化策略。sql

 

本文主要介紹SparkSQL的優化器系統Catalyst,上文講到其設計思路基本都來自於傳統型數據庫,並且和大多數當前的大數據SQL處理引擎設計基本相同(Impala、Presto、Hive(Calcite)等),所以經過本文的學習也能夠基本瞭解全部其餘SQL處理引擎的工做原理。數據庫

 

SQL優化器核心執行策略主要分爲兩個大的方向:基於規則優化(CRO)以及基於代價優化(CBO),基於規則優化是一種經驗式、啓發式地優化思路,更多地依靠前輩總結出來的優化規則,簡單易行且可以覆蓋到大部分優化邏輯,可是對於核心優化算子Join卻顯得有點力不從心。舉個簡單的例子,兩個表執行Join到底應該使用BroadcastHashJoin仍是SortMergeJoin?當前SparkSQL的方式是經過手工設定參數來肯定,若是一個表的數據量小於這個值就使用BroadcastHashJoin,可是這種方案顯得很不優雅,很不靈活。基於代價優化就是爲了解決這類問題,它會針對每一個Join評估當前兩張表使用每種Join策略的代價,根據代價估算肯定一種代價最小的方案。網絡

 

本文將會重點介紹基於規則的優化策略,後續文章會詳細介紹基於代價的優化策略。下圖中紅色框框部分將是本文的介紹重點:數據結構

 

預備知識-Tree&Rule分佈式

在介紹SQL優化器工做原理以前,有必要首先介紹兩個重要的數據結構:Tree和Rule。相信不管對SQL優化器有無瞭解,都確定知道SQL語法樹這個概念,不錯,SQL語法樹就是SQL語句經過編譯器以後會被解析成一棵樹狀結構。這棵樹會包含不少節點對象,每一個節點都擁有特定的數據類型,同時會有0個或多個孩子節點(節點對象在代碼中定義爲TreeNode對象),下圖是個簡單的示例:函數

如上圖所示,箭頭左邊表達式有3種數據類型(Literal表示常量、Attribute表示變量、Add表示動做),表示x+(1+2)。映射到右邊樹狀結構後,每一種數據類型就會變成一個節點。另外,Tree還有一個很是重要的特性,能夠經過必定的規則進行等價變換,以下圖:學習

 

上圖定義了一個等價變換規則(Rule):兩個Integer類型的常量相加能夠等價轉換爲一個Integer常量,這個規則其實很簡單,對於上文中提到的表達式x+(1+2)來講就能夠轉變爲x+3。對於程序來說,如何找到兩個Integer常量呢?其實就是簡單的二叉樹遍歷算法,每遍歷到一個節點,就模式匹配當前節點爲Add、左右子節點是Integer常量的結構,定位到以後將此三個節點替換爲一個Literal類型的節點。大數據

 

上面用一個最簡單的示例來講明等價變換規則以及如何將規則應用於語法樹。在任何一個SQL優化器中,一般會定義大量的Rule(後面會講到),SQL優化器會遍歷語法樹中每一個節點,針對遍歷到的節點模式匹配全部給定規則(Rule),若是有匹配成功的,就進行相應轉換,若是全部規則都匹配失敗,就繼續遍歷下一個節點。

 

Catalyst工做流程
任何一個優化器工做原理都大同小異:SQL語句首先經過Parser模塊被解析爲語法樹,此棵樹稱爲Unresolved Logical Plan;Unresolved Logical Plan經過Analyzer模塊藉助於數據元數據解析爲Logical Plan;此時再經過各類基於規則的優化策略進行深刻優化,獲得Optimized Logical Plan;優化後的邏輯執行計劃依然是邏輯的,並不能被Spark系統理解,此時須要將此邏輯執行計劃轉換爲Physical Plan;爲了更好的對整個過程進行理解,下文經過一個簡單示例進行解釋。

 

Parser

Parser簡單來講是將SQL字符串切分紅一個一個Token,再根據必定語義規則解析爲一棵語法樹。Parser模塊目前基本都使用第三方類庫ANTLR進行實現,好比Hive、 Presto、SparkSQL等。下圖是一個示例性的SQL語句(有兩張表,其中people表主要存儲用戶基本信息,score表存儲用戶的各類成績),經過Parser解析後的AST語法樹如右圖所示:

 

Analyzer

經過解析後的邏輯執行計劃基本有了骨架,可是系統並不知道score、sum這些都是些什麼鬼,此時須要基本的元數據信息來表達這些詞素,最重要的元數據信息主要包括兩部分:表的Scheme和基本函數信息,表的scheme主要包括表的基本定義(列名、數據類型)、表的數據格式(Json、Text)、表的物理位置等,基本函數信息主要指類信息。

Analyzer會再次遍歷整個語法樹,對樹上的每一個節點進行數據類型綁定以及函數綁定,好比people詞素會根據元數據表信息解析爲包含age、id以及name三列的表,people.age會被解析爲數據類型爲int的變量,sum會被解析爲特定的聚合函數,以下圖所示:

SparkSQL中Analyzer定義了各類解析規則,有興趣深刻了解的童鞋能夠查看Analyzer類,其中定義了基本的解析規則,以下:

 

 

Optimizer

優化器是整個Catalyst的核心,上文提到優化器分爲基於規則優化和基於代價優化兩種,當前SparkSQL 2.1依然沒有很好的支持基於代價優化(下文細講),此處只介紹基於規則的優化策略,基於規則的優化策略實際上就是對語法樹進行一次遍歷,模式匹配可以知足特定規則的節點,再進行相應的等價轉換。所以,基於規則優化說到底就是一棵樹等價地轉換爲另外一棵樹。SQL中經典的優化規則有不少,下文結合示例介紹三種比較常見的規則:謂詞下推(Predicate Pushdown)、常量累加(Constant Folding)和列值裁剪(Column Pruning)。

 

上圖左邊是通過Analyzer解析後的語法樹,語法樹中兩個表先作join,以後再使用age>10對結果進行過濾。你們知道join算子一般是一個很是耗時的算子,耗時多少通常取決於參與join的兩個表的大小,若是可以減小參與join兩表的大小,就能夠大大下降join算子所需時間。謂詞下推就是這樣一種功能,它會將過濾操做下推到join以前進行,上圖中過濾條件age>0以及id!=null兩個條件就分別下推到了join以前。這樣,系統在掃描數據的時候就對數據進行了過濾,參與join的數據量將會獲得顯著的減小,join耗時必然也會下降。

常量累加其實很簡單,就是上文中提到的規則  x+(1+2)  -> x+3,雖然是一個很小的改動,可是意義巨大。示例若是沒有進行優化的話,每一條結果都須要執行一次100+80的操做,而後再與變量math_score以及english_score相加,而優化後就不須要再執行100+80操做。

 

列值裁剪是另外一個經典的規則,示例中對於people表來講,並不須要掃描它的全部列值,而只須要列值id,因此在掃描people以後須要將其餘列進行裁剪,只留下列id。這個優化一方面大幅度減小了網絡、內存數據量消耗,另外一方面對於列存數據庫(Parquet)來講大大提升了掃描效率。

除此以外,Catalyst還定義了不少其餘優化規則,有興趣深刻了解的童鞋能夠查看Optimizer類,下圖簡單的截取一部分規則:

 

至此,邏輯執行計劃已經獲得了比較完善的優化,然而,邏輯執行計劃依然沒辦法真正執行,他們只是邏輯上可行,實際上Spark並不知道如何去執行這個東西。好比Join只是一個抽象概念,表明兩個表根據相同的id進行合併,然而具體怎麼實現這個合併,邏輯執行計劃並無說明。

 

此時就須要將邏輯執行計劃轉換爲物理執行計劃,將邏輯上可行的執行計劃變爲Spark能夠真正執行的計劃。好比Join算子,Spark根據不一樣場景爲該算子制定了不一樣的算法策略,有BroadcastHashJoin、ShuffleHashJoin以及SortMergeJoin等(能夠將Join理解爲一個接口,BroadcastHashJoin是其中一個具體實現),物理執行計劃實際上就是在這些具體實現中挑選一個耗時最小的算法實現,這個過程涉及到基於代價優化策略,後續文章細講。

 

SparkSQL執行計劃

至此,筆者經過一個簡單的示例完整的介紹了Catalyst的整個工做流程,包括Parser階段、Analyzer階段、Optimize階段以及Physical Planning階段。有同窗可能會比較感興趣Spark環境下如何查看一條具體的SQL的整個過程,在此介紹兩種方法:

1. 使用queryExecution方法查看邏輯執行計劃,使用explain方法查看物理執行計劃,分別以下所示:

2. 使用Spark WebUI進行查看,以下圖所示:

 

參考文章:

1. Deep Dive into  Spark SQL’s Catalyst Optimizer:Deep Dive into Spark SQL's Catalyst Optimizer

2. A Deep Dive into Spark SQL’s Catalyst Optimiser:

3. Spark SQL: Relational Data Processing in Spark:

4. 一個Spark SQL做業的一輩子:

 

 

網易有數:企業級大數據可視化分析平臺。面向業務人員的自助式敏捷分析平臺,採用PPT模式的報告製做,更加易學易用,具有強大的探索分析功能,真正幫助用戶洞察數據發現價值。可點擊這裏免費試用

 

瞭解 網易雲 :
網易雲官網:https://www.163yun.com/
新用戶大禮包:https://www.163yun.com/gift
網易雲社區:https://sq.163yun.com/

相關文章
相關標籤/搜索