Spark优化篇:RBO/CBO
?????? ? ??在Spark1.0中所有的Catalyst Optimizer都是基于規(guī)則 (rule) 優(yōu)化的。為了產(chǎn)生比較好的查詢規(guī) 則,優(yōu)化器需要理解數(shù)據(jù)的特性,于是在Spark2.0中引入了基于代價的優(yōu)化器 (cost-based optimizer),也就是所謂的CBO。然而,CBO也無法解決很多問題,比如:
- ?數(shù)據(jù)統(tǒng)計信息普遍缺失,統(tǒng)計信息的收集代價較高;
- 儲存計算分離的架構(gòu)使得收集到的統(tǒng)計信息可能不再準(zhǔn)確;
- Spark部署在某一單一的硬件架構(gòu)上,cost很難被估計;
- Spark的UDF(User-defined Function)簡單易用,種類繁多,但是對于CBO來說是個黑 盒子,無法估計其cost;
總而言之,由于種種限制,Spark的優(yōu)化器無法產(chǎn)生最好的Plan。
也許你會想:Spark為什么不解決這個問題呢?這里有很多挑戰(zhàn),比如:?
- 統(tǒng)計信息的缺失,統(tǒng)計信息的不準(zhǔn)確,那么就是默認(rèn)依據(jù)文件大小來預(yù)估表的大小,但是文件?往往是壓縮的,尤其是列存儲格式,比如parquet?和?ORC,而Spark是基于行處理,如果數(shù)據(jù)連續(xù)重復(fù),file size可能和真實的行存儲的真實大小,差別非常之大。這也是為何提高?autoBroadcastJoinThreshold,即使不是太大也可能會導(dǎo)致out of memory;?
- Filter復(fù)雜、UDFs的使用都會使Spark無法準(zhǔn)確估計Join輸入數(shù)據(jù)量的大小。當(dāng)你的queryplan異常大和復(fù)雜的時候,這點尤其明顯;
- 其中,Spark3.0中基于運行期的統(tǒng)計信息,將Sort Merge Join?轉(zhuǎn)換為Broadcast Hash Join。
基于RBO優(yōu)化:
left join case
var appSql: String ="""|select| *|from| tab_spark_test as t1|left join tab_spark_test_2 as t2|on t1.id = t2.id|and t1.id > 5+5""".stripMarginsparkSession.sql("use default;")sparkSession.sql(appSql).explain(mode = "extended")
基于CBO優(yōu)化:
CBO?優(yōu)化主要在物理計劃層面,原理是計算所有可能的物理計劃的代價,并挑選出代價最小的物理執(zhí)行計劃。充分考慮了數(shù)據(jù)本身的特點(如大小、分布)以及操作算子的特點(中間結(jié)果集的分布及大小)及代價,從而更好的選擇執(zhí)行代價最小的物理執(zhí)行計劃。
而每個執(zhí)行節(jié)點的代價,分為兩個部分:?
1、該執(zhí)行節(jié)點對數(shù)據(jù)集的影響,即該節(jié)點輸出數(shù)據(jù)集的大小與分布;
2、該執(zhí)行節(jié)點操作算子的代價。
每個操作算子的代價相對固定,可用規(guī)則來描述。而執(zhí)行節(jié)點輸出數(shù)據(jù)集的大小與分布,分為兩個部分:
1、初始數(shù)據(jù)集,也即原始表,其數(shù)據(jù)集的大小與分布可直接通過統(tǒng)計得到;
2、中間節(jié)點輸出數(shù)據(jù)集的大小與分布可由其輸入數(shù)據(jù)集的信息與操作本身的特點推算。
需要先執(zhí)行特定的?SQL?語句來收集所需的表和列的統(tǒng)計信息。?
--表級別統(tǒng)計信息
ANALYZE TABLE 表名 COMPUTE STATISTICS
--生成列級別統(tǒng)計信息
ANALYZE TABLE 表名 COMPUTE STATISTICS FOR COLUMNS 列 1,列 2,列 3--顯示統(tǒng)計信息
DESC FORMATTED 表名
--顯示列統(tǒng)計信息
DESC FORMATTED 表名 列名
沒有執(zhí)行 ANALYZE狀態(tài)?
執(zhí)行 ANALYZE后,發(fā)現(xiàn)多了很多spark.sql.statistics信息
?
?使用?CBO
通過?"spark.sql.cbo.enabled"?來開啟,默認(rèn)是?false。配置開啟?CBO?后,CBO?優(yōu)化器可以基于表和列的統(tǒng)計信息,進行一系列的估算,最終選擇出最優(yōu)的查詢計劃。比如:Build?側(cè)選擇、優(yōu)化?Join?類型、優(yōu)化多表?Join?順序等。
|
參數(shù) |
描述 ? ? ?? | 默認(rèn)值 |
|
spark.sql.cbo.enabled |
true?表示打開,false?表示關(guān)閉。 要使用該功能,需確保相關(guān)表和列的統(tǒng)計信息已經(jīng)生成。 |
false |
|
spark.sql.cbo.joinReorder.enabled? |
使用?CBO?來自動調(diào)整連續(xù)的?inner join?的順序。 true:表示打開,false:表示關(guān)閉 要使用該功能,需確保相關(guān)表和列的統(tǒng)計信息已經(jīng)生成,且 CBO?總開關(guān)打開。 |
false |
|
spark.sql.cbo.joinReorder.dp.threshold? |
使用?CBO?來自動調(diào)整連續(xù)?inner join?的表的個數(shù)閾值。 如果超出該閾值,則不會調(diào)整?join?順序。 |
10 |
???????
def main(args: Array[String]): Unit = {val sparkConf: SparkConf = new SparkConf().setAppName("CBO").set("spark.sql.cbo.enabled", "true").set("spark.sql.cbo.joinReorder.enabled", "true").setMaster("local[*]")val sparkSession: SparkSession = Util.SparkSession2hive(sparkConf)var appSql: String ="""|select| t1.name,count(1)|from| tab_spark_test as t1|left join tab_spark_test_2 as t2|on t1.id = t2.id|group by t1.name""".stripMarginsparkSession.sql("use default;")sparkSession.sql(appSql).show()while (true) {}}
123
總結(jié)
以上是生活随笔為你收集整理的Spark优化篇:RBO/CBO的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sdut算法分析oj题目整合
- 下一篇: excel中power函数的使用方法