精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Group By高級用法Groupings Sets語句的功能和底層實現

元閏子的邀請 ? 來源:元閏子的邀請 ? 作者:元閏子 ? 2022-07-04 10:26 ? 次閱讀

前言

SQL 中Group By語句大家都很熟悉,根據指定的規則對數據進行分組,常常和聚合函數一起使用。

比如,考慮有表dealer,表中數據如下:

id (Int) city (String) car_model (String) quantity (Int)
100 Fremont Honda Civic 10
100 Fremont Honda Accord 15
100 Fremont Honda CRV 7
200 Dublin Honda Civic 20
200 Dublin Honda Accord 10
200 Dublin Honda CRV 3
300 San Jose Honda Civic 5
300 San Jose Honda Accord 8

如果執行 SQL 語句SELECT id, sum(quantity) FROM dealer GROUP BY id ORDER BY id,會得到如下結果:

+---+-------------+
|id|sum(quantity)|
+---+-------------+
|100|32|
|200|33|
|300|13|
+---+-------------+

上述 SQL 語句的意思就是對數據按id列進行分組,然后在每個分組內對quantity列進行求和。

Group By語句除了上面的簡單用法之外,還有更高級的用法,常見的是Grouping SetsRollUpCube,它們在 OLAP 時比較常用。其中,RollUpCube都是以Grouping Sets為基礎實現的,因此,弄懂了Grouping Sets,也就理解了RollUpCube

本文首先簡單介紹Grouping Sets的用法,然后以 Spark SQL 作為切入點,深入解析Grouping Sets的實現機制。

Spark SQL 是 Apache Spark 大數據處理框架的一個子模塊,用來處理結構化信息。它可以將 SQL 語句翻譯多個任務在 Spark 集群上執行,允許用戶直接通過 SQL 來處理數據,大大提升了易用性。

Grouping Sets 簡介

Spark SQL 官方文檔中SQL Syntax一節對Grouping Sets語句的描述如下:

Groups the rows for each grouping set specified after GROUPING SETS. (... 一些舉例) This clause is a shorthand for aUNION ALLwhere each leg of theUNION ALLoperator performs aggregation of each grouping set specified in theGROUPING SETSclause. (... 一些舉例)

也即,Grouping Sets語句的作用是指定幾個grouping set作為Group By的分組規則,然后再將結果聯合在一起。它的效果和,先分別對這些 grouping set 進行Group By分組之后,再通過 Union All 將結果聯合起來,是一樣的。

比如,對于dealer表,Group By Grouping Sets ((city, car_model), (city), (car_model), ())Union All((Group By city, car_model), (Group By city), (Group By car_model), 全局聚合)的效果是相同的:

先看 Grouping Sets 版的執行結果:

spark-sql>SELECTcity,car_model,sum(quantity)ASsumFROMdealer
>GROUPBYGROUPINGSETS((city,car_model),(city),(car_model),())
>ORDERBYcity,car_model;
+--------+------------+---+
|city|car_model|sum|
+--------+------------+---+
|null|null|78|
|null|HondaAccord|33|
|null|HondaCRV|10|
|null|HondaCivic|35|
|Dublin|null|33|
|Dublin|HondaAccord|10|
|Dublin|HondaCRV|3|
|Dublin|HondaCivic|20|
|Fremont|null|32|
|Fremont|HondaAccord|15|
|Fremont|HondaCRV|7|
|Fremont|HondaCivic|10|
|SanJose|null|13|
|SanJose|HondaAccord|8|
|SanJose|HondaCivic|5|
+--------+------------+---+

再看 Union All 版的執行結果:

spark-sql>(SELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcity,car_model)UNIONALL
>(SELECTcity,NULLascar_model,sum(quantity)ASsumFROMdealerGROUPBYcity)UNIONALL
>(SELECTNULLascity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcar_model)UNIONALL
>(SELECTNULLascity,NULLascar_model,sum(quantity)ASsumFROMdealer)
>ORDERBYcity,car_model;
+--------+------------+---+
|city|car_model|sum|
+--------+------------+---+
|null|null|78|
|null|HondaAccord|33|
|null|HondaCRV|10|
|null|HondaCivic|35|
|Dublin|null|33|
|Dublin|HondaAccord|10|
|Dublin|HondaCRV|3|
|Dublin|HondaCivic|20|
|Fremont|null|32|
|Fremont|HondaAccord|15|
|Fremont|HondaCRV|7|
|Fremont|HondaCivic|10|
|SanJose|null|13|
|SanJose|HondaAccord|8|
|SanJose|HondaCivic|5|
+--------+------------+---+

兩版的查詢結果完全一樣。

Grouping Sets 的執行計劃

從執行結果上看,Grouping Sets 版本和 Union All 版本的 SQL 是等價的,但 Grouping Sets 版本更加簡潔。

那么,Grouping Sets僅僅只是Union All的一個縮寫,或者語法糖嗎

為了進一步探究Grouping Sets的底層實現是否和Union All是一致的,我們可以來看下兩者的執行計劃。

首先,我們通過explain extended來查看 Union All 版本的Optimized Logical Plan:

spark-sql>explainextended(SELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcity,car_model)UNIONALL(SELECTcity,NULLascar_model,sum(quantity)ASsumFROMdealerGROUPBYcity)UNIONALL(SELECTNULLascity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcar_model)UNIONALL(SELECTNULLascity,NULLascar_model,sum(quantity)ASsumFROMdealer)ORDERBYcity,car_model;
==ParsedLogicalPlan==
...
==AnalyzedLogicalPlan==
...
==OptimizedLogicalPlan==
Sort[city#93ASCNULLSFIRST,car_model#94ASCNULLSFIRST],true
+-Unionfalse,false
:-Aggregate[city#93,car_model#94],[city#93,car_model#94,sum(quantity#95)ASsum#79L]
:+-Project[city#93,car_model#94,quantity#95]
:+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#92,city#93,car_model#94,quantity#95],PartitionCols:[]]
:-Aggregate[city#97],[city#97,nullAScar_model#112,sum(quantity#99)ASsum#81L]
:+-Project[city#97,quantity#99]
:+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#96,city#97,car_model#98,quantity#99],PartitionCols:[]]
:-Aggregate[car_model#102],[nullAScity#113,car_model#102,sum(quantity#103)ASsum#83L]
:+-Project[car_model#102,quantity#103]
:+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#100,city#101,car_model#102,quantity#103],PartitionCols:[]]
+-Aggregate[nullAScity#114,nullAScar_model#115,sum(quantity#107)ASsum#86L]
+-Project[quantity#107]
+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#104,city#105,car_model#106,quantity#107],PartitionCols:[]]
==PhysicalPlan==
...

從上述的 Optimized Logical Plan 可以清晰地看出 Union All 版本的執行邏輯:

  1. 執行每個子查詢語句,計算得出查詢結果。其中,每個查詢語句的邏輯是這樣的:
  • HiveTableRelation節點對dealer表進行全表掃描。
  • Project節點選出與查詢語句結果相關的列,比如對于子查詢語句SELECT NULL as city, NULL as car_model, sum(quantity) AS sum FROM dealer,只需保留quantity列即可。
  • Aggregate節點完成quantity列對聚合運算。在上述的 Plan 中,Aggregate 后面緊跟的就是用來分組的列,比如Aggregate [city#902]就表示根據city列來進行分組。
  • Union節點完成對每個子查詢結果的聯合。
  • 最后,在Sort節點完成對數據的排序,上述 Plan 中Sort [city#93 ASC NULLS FIRST, car_model#94 ASC NULLS FIRST]就表示根據citycar_model列進行升序排序。
d6003622-fa88-11ec-ba43-dac502259ad0.jpg

接下來,我們通過explain extended來查看 Grouping Sets 版本的 Optimized Logical Plan:

spark-sql>explainextendedSELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYGROUPINGSETS((city,car_model),(city),(car_model),())ORDERBYcity,car_model;
==ParsedLogicalPlan==
...
==AnalyzedLogicalPlan==
...
==OptimizedLogicalPlan==
Sort[city#138ASCNULLSFIRST,car_model#139ASCNULLSFIRST],true
+-Aggregate[city#138,car_model#139,spark_grouping_id#137L],[city#138,car_model#139,sum(quantity#133)ASsum#124L]
+-Expand[[quantity#133,city#131,car_model#132,0],[quantity#133,city#131,null,1],[quantity#133,null,car_model#132,2],[quantity#133,null,null,3]],[quantity#133,city#138,car_model#139,spark_grouping_id#137L]
+-Project[quantity#133,city#131,car_model#132]
+-HiveTableRelation[`default`.`dealer`,org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,DataCols:[id#130,city#131,car_model#132,quantity#133],PartitionCols:[]]
==PhysicalPlan==
...

從 Optimized Logical Plan 來看,Grouping Sets 版本要簡潔很多!具體的執行邏輯是這樣的:

  1. HiveTableRelation節點對dealer表進行全表掃描。
  2. Project節點選出與查詢語句結果相關的列。
  3. 接下來的Expand節點是關鍵,數據經過該節點后,多出了spark_grouping_id列。從 Plan 中可以看出來,Expand 節點包含了Grouping Sets里的各個 grouping set 信息,比如[quantity#133, city#131, null, 1]對應的就是(city)這一 grouping set。而且,每個 grouping set 對應的spark_grouping_id列的值都是固定的,比如(city)對應的spark_grouping_id1
  4. Aggregate節點完成quantity列對聚合運算,其中分組的規則為city, car_model, spark_grouping_id。注意,數據經過 Aggregate 節點后,spark_grouping_id列被刪除了!
  5. 最后,在Sort節點完成對數據的排序。
d62993fa-fa88-11ec-ba43-dac502259ad0.jpg

從 Optimized Logical Plan 來看,雖然 Union All 版本和 Grouping Sets 版本的效果一致,但它們的底層實現有著巨大的差別。

其中,Grouping Sets 版本的 Plan 中最關鍵的是 Expand 節點,目前,我們只知道數據經過它之后,多出了spark_grouping_id列。而且從最終結果來看,spark_grouping_id只是 Spark SQL 的內部實現細節,對用戶并不體現。那么:

  1. Expand 的實現邏輯是怎樣的,為什么能達到Union All的效果?
  2. Expand 節點的輸出數據是怎樣的
  3. spark_grouping_id列的作用是什么

通過 Physical Plan,我們發現 Expand 節點對應的算子名稱也是Expand:

==PhysicalPlan==
AdaptiveSparkPlanisFinalPlan=false
+-Sort[city#138ASCNULLSFIRST,car_model#139ASCNULLSFIRST],true,0
+-Exchangerangepartitioning(city#138ASCNULLSFIRST,car_model#139ASCNULLSFIRST,200),ENSURE_REQUIREMENTS,[plan_id=422]
+-HashAggregate(keys=[city#138,car_model#139,spark_grouping_id#137L],functions=[sum(quantity#133)],output=[city#138,car_model#139,sum#124L])
+-Exchangehashpartitioning(city#138,car_model#139,spark_grouping_id#137L,200),ENSURE_REQUIREMENTS,[plan_id=419]
+-HashAggregate(keys=[city#138,car_model#139,spark_grouping_id#137L],functions=[partial_sum(quantity#133)],output=[city#138,car_model#139,spark_grouping_id#137L,sum#141L])
+-Expand[[quantity#133,city#131,car_model#132,0],[quantity#133,city#131,null,1],[quantity#133,null,car_model#132,2],[quantity#133,null,null,3]],[quantity#133,city#138,car_model#139,spark_grouping_id#137L]
+-Scanhivedefault.dealer[quantity#133,city#131,car_model#132],HiveTableRelation[`default`.`dealer`,...,DataCols:[id#130,city#131,car_model#132,quantity#133],PartitionCols:[]]

帶著前面的幾個問題,接下來我們深入 Spark SQL 的Expand算子源碼尋找答案。

Expand 算子的實現

Expand 算子在 Spark SQL 源碼中的實現為ExpandExec類(Spark SQL 中的算子實現類的命名都是XxxExec的格式,其中Xxx為具體的算子名,比如 Project 算子的實現類為ProjectExec),核心代碼如下:

/**
*ApplyalloftheGroupExpressionstoeveryinputrow,hencewewillget
*multipleoutputrowsforaninputrow.
*@paramprojectionsThegroupofexpressions,allofthegroupexpressionsshould
*outputthesameschemaspecifiedbyetheparameter`output`
*@paramoutputTheoutputSchema
*@paramchildChildoperator
*/
caseclassExpandExec(
projections:Seq[Seq[Expression]],
output:Seq[Attribute],
child:SparkPlan)
extendsUnaryExecNodewithCodegenSupport{

...
//關鍵點1,將child.output,也即上游算子輸出數據的schema,
//綁定到表達式數組exprs,以此來計算輸出數據
private[this]valprojection=
(exprs:Seq[Expression])=>UnsafeProjection.create(exprs,child.output)

//doExecute()方法為Expand算子執行邏輯所在
protectedoverridedefdoExecute():RDD[InternalRow]={
valnumOutputRows=longMetric("numOutputRows")

//處理上游算子的輸出數據,Expand算子的輸入數據就從iter迭代器獲取
child.execute().mapPartitions{iter=>
//關鍵點2,projections對應了GroupingSets里面每個groupingset的表達式,
//表達式輸出數據的schema為this.output,比如(quantity,city,car_model,spark_grouping_id)
//這里的邏輯是為它們各自生成一個UnsafeProjection對象,通過該對象的apply方法就能得出Expand算子的輸出數據
valgroups=projections.map(projection).toArray
newIterator[InternalRow]{
private[this]varresult:InternalRow=_
private[this]varidx=-1//-1meanstheinitialstate
private[this]varinput:InternalRow=_

overridefinaldefhasNext:Boolean=(-1overridefinaldefnext():InternalRow={
//關鍵點3,對于輸入數據的每一條記錄,都重復使用N次,其中N的大小對應了projections數組的大小,
//也即GroupingSets里指定的groupingset的數量
if(idx<=?0){
//intheinitial(-1)orbeginning(0)ofanewinputrow,fetchthenextinputtuple
input=iter.next()
idx=0
}
//關鍵點4,對輸入數據的每一條記錄,通過UnsafeProjection計算得出輸出數據,
//每個groupingset對應的UnsafeProjection都會對同一個input計算一遍
result=groups(idx)(input)
idx+=1

if(idx==groups.length&&iter.hasNext){
idx=0
}

numOutputRows+=1
result
}
}
}
}
...
}

ExpandExec的實現并不復雜,想要理解它的運作原理,關鍵是看懂上述源碼中提到的 4 個關鍵點。

關鍵點 1關鍵點 2是基礎,關鍵點 2中的groups是一個UnsafeProjection[N]數組類型,其中每個UnsafeProjection代表了Grouping Sets語句里指定的 grouping set,它的定義是這樣的:

//AprojectionthatreturnsUnsafeRow.
abstractclassUnsafeProjectionextendsProjection{
overridedefapply(row:InternalRow):UnsafeRow
}

//Thefactoryobjectfor`UnsafeProjection`.
objectUnsafeProjection
extendsCodeGeneratorWithInterpretedFallback[Seq[Expression],UnsafeProjection]{
//ReturnsanUnsafeProjectionforgivensequenceofExpressions,whichwillbeboundto
//`inputSchema`.
defcreate(exprs:Seq[Expression],inputSchema:Seq[Attribute]):UnsafeProjection={
create(bindReferences(exprs,inputSchema))
}
...
}

UnsafeProjection起來了類似列投影的作用,其中,apply方法根據創建時的傳參exprsinputSchema,對輸入記錄進行列投影,得出輸出記錄。

比如,前面的GROUPING SETS ((city, car_model), (city), (car_model), ())例子,它對應的groups是這樣的:

d647af3e-fa88-11ec-ba43-dac502259ad0.jpg

其中,AttributeReference類型的表達式,在計算時,會直接引用輸入數據對應列的值;Iteral類型的表達式,在計算時,值是固定的。

關鍵點 3關鍵點 4是 Expand 算子的精華所在,ExpandExec通過這兩段邏輯,將每一個輸入記錄,擴展(Expand)成 N 條輸出記錄。

關鍵點 4groups(idx)(input)等同于groups(idx).apply(input)

還是以前面GROUPING SETS ((city, car_model), (city), (car_model), ())為例子,效果是這樣的:

d65cc356-fa88-11ec-ba43-dac502259ad0.jpg

到這里,我們已經弄清楚 Expand 算子的工作原理,再回頭看前面提到的 3 個問題,也不難回答了:

  1. Expand 的實現邏輯是怎樣的,為什么能達到Union All的效果?

    如果說Union All是先聚合再聯合,那么 Expand 就是先聯合再聚合。Expand 利用groups里的 N 個表達式對每條輸入記錄進行計算,擴展成 N 條輸出記錄。后面再聚合時,就能達到與Union All一樣的效果了。

  2. Expand 節點的輸出數據是怎樣的

    在 schema 上,Expand 輸出數據會比輸入數據多出spark_grouping_id列;在記錄數上,是輸入數據記錄數的 N 倍。

  3. spark_grouping_id列的作用是什么

    spark_grouping_id給每個 grouping set 進行編號,這樣,即使在 Expand 階段把數據先聯合起來,在 Aggregate 階段(把spark_grouping_id加入到分組規則)也能保證數據能夠按照每個 grouping set 分別聚合,確保了結果的正確性。

查詢性能對比

從前文可知,Grouping Sets 和 Union All 兩個版本的 SQL 語句有著一樣的效果,但是它們的執行計劃卻有著巨大的差別。下面,我們將比對兩個版本之間的執行性能差異。

spark-sql 執行完 SQL 語句之后會打印耗時信息,我們對兩個版本的 SQL 分別執行 10 次,得到如下信息:

//GroupingSets版本執行10次的耗時信息
//SELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYGROUPINGSETS((city,car_model),(city),(car_model),())ORDERBYcity,car_model;
Timetaken:0.289seconds,Fetched15row(s)
Timetaken:0.251seconds,Fetched15row(s)
Timetaken:0.259seconds,Fetched15row(s)
Timetaken:0.258seconds,Fetched15row(s)
Timetaken:0.296seconds,Fetched15row(s)
Timetaken:0.247seconds,Fetched15row(s)
Timetaken:0.298seconds,Fetched15row(s)
Timetaken:0.286seconds,Fetched15row(s)
Timetaken:0.292seconds,Fetched15row(s)
Timetaken:0.282seconds,Fetched15row(s)

//UnionAll版本執行10次的耗時信息
//(SELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcity,car_model)UNIONALL(SELECTcity,NULLascar_model,sum(quantity)ASsumFROMdealerGROUPBYcity)UNIONALL(SELECTNULLascity,car_model,sum(quantity)ASsumFROMdealerGROUPBYcar_model)UNIONALL(SELECTNULLascity,NULLascar_model,sum(quantity)ASsumFROMdealer)ORDERBYcity,car_model;
Timetaken:0.628seconds,Fetched15row(s)
Timetaken:0.594seconds,Fetched15row(s)
Timetaken:0.591seconds,Fetched15row(s)
Timetaken:0.607seconds,Fetched15row(s)
Timetaken:0.616seconds,Fetched15row(s)
Timetaken:0.64seconds,Fetched15row(s)
Timetaken:0.623seconds,Fetched15row(s)
Timetaken:0.625seconds,Fetched15row(s)
Timetaken:0.62seconds,Fetched15row(s)
Timetaken:0.62seconds,Fetched15row(s)

可以算出,Grouping Sets 版本的 SQL 平均耗時為0.276s;Union All 版本的 SQL 平均耗時為0.616s,是前者的2.2 倍

所以,Grouping Sets 版本的 SQL 不僅在表達上更加簡潔,在性能上也更加高效

RollUp 和 Cube

Group By的高級用法中,還有RollUpCube兩個比較常用。

首先,我們看下RollUp語句

Spark SQL 官方文檔中SQL Syntax一節對RollUp語句的描述如下:

Specifies multiple levels of aggregations in a single statement. This clause is used to compute aggregations based on multiple grouping sets.ROLLUPis a shorthand forGROUPING SETS. (... 一些例子)

官方文檔中,把RollUp描述為Grouping Sets的簡寫,等價規則為:RollUp(A, B, C) == Grouping Sets((A, B, C), (A, B), (A), ())

比如,Group By RollUp(city, car_model)就等同于Group By Grouping Sets((city, car_model), (city), ())

下面,我們通過expand extended看下 RollUp 版本 SQL 的 Optimized Logical Plan:

spark-sql>explainextendedSELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYROLLUP(city,car_model)ORDERBYcity,car_model;
==ParsedLogicalPlan==
...
==AnalyzedLogicalPlan==
...
==OptimizedLogicalPlan==
Sort[city#2164ASCNULLSFIRST,car_model#2165ASCNULLSFIRST],true
+-Aggregate[city#2164,car_model#2165,spark_grouping_id#2163L],[city#2164,car_model#2165,sum(quantity#2159)ASsum#2150L]
+-Expand[[quantity#2159,city#2157,car_model#2158,0],[quantity#2159,city#2157,null,1],[quantity#2159,null,null,3]],[quantity#2159,city#2164,car_model#2165,spark_grouping_id#2163L]
+-Project[quantity#2159,city#2157,car_model#2158]
+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#2156,city#2157,car_model#2158,quantity#2159],PartitionCols:[]]
==PhysicalPlan==
...

從上述 Plan 可以看出,RollUp底層實現用的也是 Expand 算子,說明RollUp確實是基于Grouping Sets實現的。 而且Expand [[quantity#2159, city#2157, car_model#2158, 0], [quantity#2159, city#2157, null, 1], [quantity#2159, null, null, 3]]也表明RollUp符合等價規則。

下面,我們按照同樣的思路,看下Cube語句

Spark SQL 官方文檔中SQL Syntax一節對Cube語句的描述如下:

CUBEclause is used to perform aggregations based on combination of grouping columns specified in theGROUP BYclause.CUBEis a shorthand forGROUPING SETS. (... 一些例子)

同樣,官方文檔把Cube描述為Grouping Sets的簡寫,等價規則為:Cube(A, B, C) == Grouping Sets((A, B, C), (A, B), (A, C), (B, C), (A), (B), (C), ())

比如,Group By Cube(city, car_model)就等同于Group By Grouping Sets((city, car_model), (city), (car_model), ())

下面,我們通過expand extended看下 Cube 版本 SQL 的 Optimized Logical Plan:

spark-sql>explainextendedSELECTcity,car_model,sum(quantity)ASsumFROMdealerGROUPBYCUBE(city,car_model)ORDERBYcity,car_model;
==ParsedLogicalPlan==
...
==AnalyzedLogicalPlan==
...
==OptimizedLogicalPlan==
Sort[city#2202ASCNULLSFIRST,car_model#2203ASCNULLSFIRST],true
+-Aggregate[city#2202,car_model#2203,spark_grouping_id#2201L],[city#2202,car_model#2203,sum(quantity#2197)ASsum#2188L]
+-Expand[[quantity#2197,city#2195,car_model#2196,0],[quantity#2197,city#2195,null,1],[quantity#2197,null,car_model#2196,2],[quantity#2197,null,null,3]],[quantity#2197,city#2202,car_model#2203,spark_grouping_id#2201L]
+-Project[quantity#2197,city#2195,car_model#2196]
+-HiveTableRelation[`default`.`dealer`,...,DataCols:[id#2194,city#2195,car_model#2196,quantity#2197],PartitionCols:[]]
==PhysicalPlan==
...

從上述 Plan 可以看出,Cube底層用的也是 Expand 算子,說明Cube確實基于Grouping Sets實現,而且也符合等價規則。

所以,RollUpCube可以看成是Grouping Sets的語法糖,在底層實現和性能上是一樣的。

最后

本文重點討論了Group By高級用法Groupings Sets語句的功能和底層實現。

雖然Groupings Sets的功能,通過Union All也能實現,但前者并非后者的語法糖,它們的底層實現完全不一樣。Grouping Sets采用的是先聯合再聚合的思路,通過spark_grouping_id列來保證數據的正確性;Union All則采用先聚合再聯合的思路。Grouping Sets在 SQL 語句表達和性能上都有更大的優勢

Group By的另外兩個高級用法RollUpCube則可以看成是Grouping Sets的語法糖,它們的底層都是基于 Expand 算子實現,在性能上與直接使用Grouping Sets是一樣的,但在 SQL 表達上更加簡潔

文章配圖

可以在用Keynote畫出手繪風格的配圖中找到文章的繪圖方法。


原文標題:深入理解 SQL 中的 Grouping Sets 語句

文章出處:【微信公眾號:元閏子的邀請】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SQL
    SQL
    +關注

    關注

    1

    文章

    760

    瀏覽量

    44070
  • Group
    +關注

    關注

    0

    文章

    6

    瀏覽量

    6434

原文標題:深入理解 SQL 中的 Grouping Sets 語句

文章出處:【微信號:yuanrunzi,微信公眾號:元閏子的邀請】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    C語言中位運算符的高級用法(2)

    在上一篇文章中,我們介紹了&運算符的高級用法,本篇文章,我們將介紹| 運算符的一些高級用法
    發表于 08-22 10:45 ?311次閱讀
    C語言中位運算符的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>(2)

    C語言中位運算符的高級用法(3)

    在上一篇文章中,我們介紹了|運算符的高級用法,本篇文章,我們將介紹^ 運算符的一些高級用法
    發表于 08-22 10:47 ?238次閱讀
    C語言中位運算符的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>(3)

    C語言中位運算符的高級用法(4)

    在上一篇文章中,我們介紹了^運算符的高級用法,本篇文章,我們將介紹~ 運算符的一些高級用法
    發表于 08-22 10:48 ?213次閱讀
    C語言中位運算符的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>(4)

    C語言中位運算符的高級用法(5)

    在上一篇文章中,我們介紹了~運算符的高級用法,本篇文章,我們將介紹
    發表于 08-22 10:49 ?312次閱讀
    C語言中位運算符的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>(5)

    Rust的 match 語句用法

    執行不同的代碼,這在處理復雜的邏輯時非常有用。在本教程中,我們將深入了解 Rust 的 match 語句,包括基礎用法、進階用法和實踐經驗等方面。 基礎用法 match
    的頭像 發表于 09-19 17:08 ?885次閱讀

    求助if 語句用法

    查了 if 相關嵌套的用法 好像沒有下面這樣用的語句
    發表于 08-19 15:49

    verilog中generate語句用法分享

    ,使用生成語句能大大簡化程序的編寫過程。Verilog-2001添加了generate循環,允許產生module和primitive的多個實例化,generate語句的最主要功能就是對module、reg
    發表于 12-23 16:59

    高級語句程序設計(C++)經典試題及答案

    高級語句程序設計(C++)經典試題及答案
    發表于 12-30 14:50 ?0次下載

    SQL的經典語句用法詳細說明

    本文檔的主要內容詳細介紹的是SQL的經典語句用法詳細說明資料免費下載
    發表于 10-22 16:11 ?5次下載

    #define的高級用法簡介

    #define的高級用法
    的頭像 發表于 02-05 11:50 ?3869次閱讀

    深度剖析SQL中的Grouping Sets語句1

    SQL 中 `Group By` 語句大家都很熟悉, **根據指定的規則對數據進行分組** ,常常和**聚合函數**一起使用。
    的頭像 發表于 05-10 17:44 ?679次閱讀
    深度剖析SQL中的Grouping <b class='flag-5'>Sets</b><b class='flag-5'>語句</b>1

    深度剖析SQL中的Grouping Sets語句2

    SQL 中 `Group By` 語句大家都很熟悉, **根據指定的規則對數據進行分組** ,常常和**聚合函數**一起使用。
    的頭像 發表于 05-10 17:44 ?575次閱讀
    深度剖析SQL中的Grouping <b class='flag-5'>Sets</b><b class='flag-5'>語句</b>2

    sql語句中having的用法

    在SQL語句中,HAVING是一個用于對GROUP BY子句的結果進行過濾和限制的子句。它類似于WHERE子句,但作用于聚合函數的結果而不是單獨的行。HAVING子句通常用于對聚合函數的結果進行條件
    的頭像 發表于 11-23 11:23 ?2290次閱讀

    assign語句和always語句用法

    用法功能。 一、Assign語句 Assign語句的定義和語法 Assign語句用于在HDL中連續賦值,它允許在設計中為信號或變量分配一
    的頭像 發表于 02-22 16:24 ?2289次閱讀

    AWTK 開源串口屏開發(10) - 告警信息的高級用法

    告警信息是串口屏常用的功能,之前我們介紹了告警信息的基本用法實現了告警信息的顯示和管理。本文介紹一下實現查詢告警信息和查看告警信息詳情的方法。1.
    的頭像 發表于 02-24 08:23 ?289次閱讀
    AWTK 開源串口屏開發(10) - 告警信息的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>