sparkの物理的な計画を理解しようとしていますが、一部の部分は従来のrdbmsとは異なるため、理解できません。たとえば、以下のこの計画では、 Hiveテーブル。クエリは次のとおりです。
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= '1998-09-16'
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus;
== Physical Plan ==
Sort [l_returnflag#35 ASC,l_linestatus#36 ASC], true, 0
+- ConvertToUnsafe
+- Exchange rangepartitioning(l_returnflag#35 ASC,l_linestatus#36 ASC,200), None
+- ConvertToSafe
+- TungstenAggregate(key=[l_returnflag#35,l_linestatus#36], functions=[(sum(l_quantity#31),mode=Final,isDistinct=false),(sum(l_extendedpr#32),mode=Final,isDistinct=false),(sum((l_extendedprice#32 * (1.0 - l_discount#33))),mode=Final,isDistinct=false),(sum(((l_extendedprice#32 * (1.0l_discount#33)) * (1.0 + l_tax#34))),mode=Final,isDistinct=false),(avg(l_quantity#31),mode=Final,isDistinct=false),(avg(l_extendedprice#32),mode=Fl,isDistinct=false),(avg(l_discount#33),mode=Final,isDistinct=false),(count(1),mode=Final,isDistinct=false)], output=[l_returnflag#35,l_linestatus,sum_qty#0,sum_base_price#1,sum_disc_price#2,sum_charge#3,avg_qty#4,avg_price#5,avg_disc#6,count_order#7L])
+- TungstenExchange hashpartitioning(l_returnflag#35,l_linestatus#36,200), None
+- TungstenAggregate(key=[l_returnflag#35,l_linestatus#36], functions=[(sum(l_quantity#31),mode=Partial,isDistinct=false),(sum(l_exdedprice#32),mode=Partial,isDistinct=false),(sum((l_extendedprice#32 * (1.0 - l_discount#33))),mode=Partial,isDistinct=false),(sum(((l_extendedpri32 * (1.0 - l_discount#33)) * (1.0 + l_tax#34))),mode=Partial,isDistinct=false),(avg(l_quantity#31),mode=Partial,isDistinct=false),(avg(l_extendedce#32),mode=Partial,isDistinct=false),(avg(l_discount#33),mode=Partial,isDistinct=false),(count(1),mode=Partial,isDistinct=false)], output=[l_retulag#35,l_linestatus#36,sum#64,sum#65,sum#66,sum#67,sum#68,count#69L,sum#70,count#71L,sum#72,count#73L,count#74L])
+- Project [l_discount#33,l_linestatus#36,l_tax#34,l_quantity#31,l_extendedprice#32,l_returnflag#35]
+- Filter (l_shipdate#37 <= 1998-09-16)
+- HiveTableScan [l_discount#33,l_linestatus#36,l_tax#34,l_quantity#31,l_extendedprice#32,l_shipdate#37,l_returnflag#35], astoreRelation default, lineitem, None
私が計画で理解していることは:
最初にHiveテーブルスキャンを開始します
次に、条件を使用してフィルタリングします
次に、必要な列を取得するために投影します
次に、TungstenAggregate?
次に、TungstenExchange?
その後、TungstenAggregate?
次にConvertToSafe?
次に、最終結果を並べ替えます
しかし、私は4、5、6、7ステップを理解していません。あなたは彼らが何であるか知っていますか?計画を理解できるように、これについての情報を探していますが、具体的なことは何も見つかりません。
使用するSQLクエリの構造を見てみましょう。
_SELECT
... -- not aggregated columns #1
... -- aggregated columns #2
FROM
... -- #3
WHERE
... -- #4
GROUP BY
... -- #5
ORDER BY
... -- #6
_
あなたがすでに疑っているように:
Filter (...)
は、WHERE
句の述語に対応します(_#4
_)Project ...
_は、列の数を(_#1
_と_#2
_の和集合で必要なものに制限します。_#4
_/_#6
_がSELECT
にない場合)HiveTableScan
はFROM
句に対応します(_#3
_)残りのパーツは次のように帰属できます。
#2
_ from SELECT
句-functions
のTungstenAggregates
フィールド_GROUP BY
_句(_#5
_):
TungstenExchange
/ハッシュ分割key
のTungstenAggregates
フィールド_#6
_-_ORDER BY
_句。
Project Tungstenは、一般的にSpark DataFrames
(-sets
)が使用する一連の最適化について説明しています。
Sun.misc.Unsafe
_による明示的なメモリ管理。これは、「ネイティブ」(ヒープ以外)のメモリ使用量と明示的なメモリ割り当て/ GC管理外での解放を意味します。これらの変換は、実行プランのConvertToUnsafe
/ConvertToSafe
ステップに対応しています。 unsafeに関する興味深い詳細は nderstanding Sun.misc.Unsafe から学ぶことができます。Project Tungsten:Bringing Apache Spark Closer to Bare Metal 。 Apache Spark = 2.0:より速く、より簡単で、よりスマート コード生成の例をいくつか示します。
TungstenAggregate
が2回発生するのは、データが最初に各パーティションでローカルに集計されてから、シャッフルされ、最後にマージされるためです。 RDD APIに精通している場合、このプロセスはreduceByKey
とほぼ同じです。
実行計画が明確でない場合は、結果のDataFrame
をRDD
に変換して、toDebugString
の出力を分析することもできます。
タングステンは、1.4以降のSparkの新しいメモリエンジンであり、JVMの外部でデータを管理して、GCのオーバーヘッドを節約します。 JVMとの間でデータをコピーすることを想像してみてください。それでおしまい。 Spark 1.5ではspark.sql.tungsten.enabled
を介してタングステンをオフにでき、「古い」プランがSparkに表示されます1.6もうオフにできないと思います。