一、Catalyst 概述
- Catalyst 是 Spark SQL 的優化器,它負責將 SQL 查詢轉換為物理執行計劃。Catalyst 優化器的目標是生成高效的執行計劃,以最小化查詢的執行時間。它使用了多種優化技術,包括基于規則的優化、基于代價的優化和動態規劃等。
- 我們寫的SQL語句,會經過一個優化器(catalyst),轉化為RDD,交給集群執行。
select * from table_a - 語法。select * table_a
- 詞法。selectS * from table_a
- AST。abstract syntax tree / 抽象語法樹 / 語法樹 / syntax tree
暫時無法在飛書文檔外展示此內容 - 解析引擎:負責將SQL解析成task。Catalyst的地位類似于Calcite(負責Hive SQL解析優化),Spark SQL獨有的Catalyst,解析優化。
- MySQL
- Hive SQL
- Spark SQL
- Flink SQL
- Doris
- Presto
- 計算引擎:task是誰來執行。
- MySQL
- MapReduce
- Spark
- Tez
- Flink
- Spark on Hive和 Hive on spark的區別?
- Hive on Spark:Hive是Hive SQL,解析引擎;Spark是計算引擎。
- Spark on Hive:
- Hive
- 代表是數倉(常見的分層);
- 理解:Hive SQL,解析引擎。
- Spark:代表解析引擎、計算引擎。
- 含義:通過spark SQL做數倉,層與層的轉換。
- Hive
- SQL到RDD中間經過了一個Catalyst,它就是SparkSQL的核心,是計對 Spark SQL語句執行過程中的查詢優化框架,基于Scala函數式編程結構。
- RDD的運行流程:RDD->DAGScheduler ->TaskScheduler->worrker,任務會按照代碼所示運行,依賴開發者的優化,開發者的會在很大程度上影響運行效率。而SparkSQL的Dataset和SQL并不是直接生成計劃交給集群執行,而是經過Catalyst的優化器,這個優化器能夠自動幫助開發者優化代碼
- 我們要了解SparkSQL的執行流程,那么理解Catalyst的工作流程是非常有必要的。
二、 Catalyst 的優化過程
暫時無法在飛書文檔外展示此內容
Catalyst 的優化過程大致可以分為以下幾個階段:
- 解析 ( Parsing ):將 SQL 查詢解析為抽象語法樹 ( AST )。parser模塊目前都是使用第三方類庫ANTLR進行實現的。在這個過程匯總,會判斷SQL語句是否符合規范,比如select from where等這些關鍵字是否寫對。
暫時無法在飛書文檔外展示此內容 - 分析 ( Analysis ):對 AST 進行語義分析,檢查查詢的合法性和完整性。該模塊會遍歷整個AST,并對AST上的每個節點進行數據類型綁定以及函數綁定,然后根據源數據信息系catelog對數據表中的字段進行解析,此過程會判斷SQL語句的表名,字段名是否真的在元數據庫里存在。元數據信息主要包括兩部分:表的scheme和基本函數信息。
- 表的scheme:
1. 基本定義。列名,數據類型。
2. 表的數據格式。json、text
3. 表的物理位置。 - 基本函數
暫時無法在飛書文檔外展示此內容 - 優化 ( Optimization ):應用各種優化規則和策略,生成不同的執行計劃。主要分為RBO和CBO兩種優化策略,其中RBO(Rule-Based Optimizer)是基于規則優化,CBO(Cost-Based Optimizer)是基于代價優化。常見的規則有:
- 謂詞下推predicate Pushdown:將過濾操作下推到join之前進行,之后在進行join的時候,數據量將會顯著的減少,join耗時必然降低。
暫時無法在飛書文檔外展示此內容
select*
from table1
inner jointable2
on table1.id = table2.id
where table1.age > 20and table2.cid = 1
上面的語句會自動優化為如下所示:
select*
from
(select *fromtable1where table1.age > 20
) a
inner join
(select *fromtable2where table2.cid = 1
) b
on a.id = b.id
即在資產許那階段就提前將數據進行過濾,后續的join和shuffle數據量會大大減少。
- 列值裁剪column pruning:在謂詞下推后,可以把表中沒有用到的列裁剪掉,這一優化一方面大幅度減少了網絡,內存的數據量消耗,另一方面對于劣勢存儲數據庫來說大大提高了掃描效率。
selecta.name,a.age,b.cid
from
(select *fromtable1where table1.age > 20
) a
inner join
(select *fromtable2where table2.cid = 1
) b
on a.id = b.id
上面的語句會自動優化如下圖所示:
selecta.name,a.age,b.cid
from
(select name,agefromtable1where table1.age > 20
) a
inner join
(select cidfromtable2where table2.cid = 1
) b
on a.id = b.id
就是提前將需要的列查詢出來,其他不需要的列裁剪掉。
- 常量累加 constant folding:比如計算 x + (100 + 80) -> x + 180,雖然是一個很小的改動,但是意義巨大。如果沒有進行優化,每一條結果都需要執行一次100 + 80的操作,然后再與結果相加,優化后就不需要再次執行100 + 80的操作。
select 1 + 1 id
fromtable1
上面的語句會自動優化如下圖所示:
select 2 id
fromtable1
就是會提前將1 + 1計算成2,再賦給id列的每行,不用每次都計算一次1+1
4. SparkPlanner模塊:
- 將優化后的邏輯執行計劃(OptimizedLogicalPlan)轉換成Physical Plan(物理計劃),也就是Spark可以真正的執行的計劃。比如join算子,Spark根據不同常見為該算子制定了不同的算法策略,有BroadCastHashJoin,ShuffleHashJoin以及SortMergeJoin等,物理執行假話實際上就是在這些具體實現中挑選一個耗時最小的算法實現。
- 具體的實現手段:
1. SparkPlanner對優化后的邏輯計劃進行換算,是生成了多個可以執行的物理計劃Physical Plan;接著CBO(基于代價優化)優化策略或根據Cost Model算出每個Physical Plan的代價,并選取最小代價的Physical Plan作最終的Physical Plan。
2. CostmModel模塊:主要根據過去的性能統計數據,選擇最佳的物理執行計劃,這個過程的優化就是CBO(基于代價優化)
備注:以上2、3、4步驟結合起來,就是catalyst優化器。 - 執行物理計劃:最后一句最優的物理執行計劃,生成Java字節碼,將SQL轉化為DAG,以RDD的形式進行操作
- 選擇 ( Selection ):根據代價模型選擇最優的執行計劃。
- 代碼生成 ( Code Generation ):將優化后的執行計劃轉換為 Spark 代碼。
三、 Catalyst 的優化規則
Catalyst 提供了許多優化規則,用于改進查詢的執行計劃。以下是一些常見的優化規則: - 列剪枝 ( Column Pruning ):刪除不必要的列,減少數據傳輸。
- 分區剪枝 ( Partition Pruning ):根據分區過濾條件,只讀取必要的分區。
- 謂詞下推 ( Predicate Pushdown ):將過濾條件盡可能地向下推送到數據源,減少數據的讀取量。
- 聚合優化 ( Aggregation Optimization ):合并相同的聚合操作,避免重復計算。
- 連接優化 ( Join Optimization ):選擇合適的連接算法,優化連接操作。
四、 Catalyst 的代價模型
Catalyst 采用了基于規則的代價模型來評估執行計劃的代價。代價模型考慮了以下因素: - 數據量 ( Data Volume ):表的數據大小和分區數。
- 計算資源 ( Compute Resources ):CPU、內存和網絡帶寬等。
- I/O 開銷 ( I/O Overhead ):數據讀取和寫入的開銷。
- 數據傾斜 ( Data Skew ):數據分布不均衡導致的性能問題。
五、 Catalyst 的代碼生成
Catalyst 將優化后的執行計劃轉換為 Spark 代碼,包括RDD操作和SQL表達式。代碼生成過程使用了模板和宏來實現代碼的重用和簡潔性。
六、總結
Spark SQL 的 Catalyst 優化器是一個強大而靈活的優化框架,它采用了多種優化技術和策略,以生成高效的執行計劃。了解 Catalyst 的優化過程和規則,可以幫助我們更好地編寫高效的 Spark SQL 查詢。
以上是一個關于 Spark SQL 優化器 Catalyst 的學習文檔,希望對你有所幫助。如果你有任何問題或建議,請隨時與我交流。