SparkSQL子查询和性能

时间:2018-11-11 07:50:55

标签: apache-spark apache-spark-sql

为了允许系统用户动态(通过应用程序Web UI)创建带有辅助数据的不同数据字典,我使用DataFrames并将它们公开为临时表,例如:

foreach ($array['OPMWebBlog'] as $item) {
    echo $item['WebTitle'];
    echo $item['WebBody'];
    ...
}

这些词典的数量仅受用户想象力和业务需求的限制。

此后,用户还创建不同的查询,这些查询可以使用基于先前定义的辅助数据的条件,例如SQL Seq("Italy", "France", "United States", "Spain").toDF("country").createOrReplaceTempView("big_countries") Seq("Poland", "Hungary", "Spain").toDF("country").createOrReplaceTempView("medium_countries") 条件:

WHERE

这些查询的数量仅受用户想象力和业务需求的限制。

我现在最担心的是像Q1: country IN (FROM medium_countries) Q2: (TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL) AND phone = '+91-9111999998' Q3: TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL ...... Qn: name = 'Donald' AND email = 'donald@example.com' AND phone = '+1-2222222222'

这样的子查询

根据系统设计,这里我不能使用显式country IN (FROM medium_countries),因此我只能使用子查询。因此,我有一个问题-这些辅助数据表的大小通常应该相对较小...我认为最坏情况下的几千行和这些表的总数-最坏情况下的几百行。考虑到这一点,这种方法是否会导致性能问题,是否存在可以优化流程的技术,例如将这些字典缓存在内存中等等?

已更新

现在我只能在Spark本地模式下对其进行测试

查询:

JOIN

执行计划:

country IN (FROM big_countries)

查询:

+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|plan                                                                                                                                                                                                                                                                                                                                                                            |tag|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|== Physical Plan ==
*(1) Project [unique_id#27L]
+- *(1) BroadcastHashJoin [country#22], [country#3], LeftSemi, BuildRight
   :- *(1) Project [country#22, unique_id#27L]
   :  +- LocalTableScan [name#19, email#20, phone#21, country#22, unique_id#27L]
   +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, string, true]))
      +- LocalTableScan [country#3]|big|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+

执行计划:

TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL

1 个答案:

答案 0 :(得分:1)

我认为:

#? version_file
    checkout

#? final_target
    $0 version_file     # Static dependency
    version=$(get version from version_file)
    $0 file_$version    # Dynamic dependency

是在执行以下操作之后需要执行的操作:

CACHE TABLE tbl  as in sql("CACHE TABLE tbl")

但当然要先进行较大的查询。

现在在SPARK中,默认情况下,上面关于“缓存”的声明现在很急,而不是偷懒。如手册所述,您不再需要手动触发缓存实现。也就是说,不再需要执行df.show或df.count。

一旦在内存中-在您明确刷新之前,不需要再次获取此数据,并且这里看起来好像没有过滤,而是只需加载所有有限的数据集一次即可。

不知道您的设计,但看着它,子查询应该没问题。尝试这种方法并查看物理计划。在传统的RDBMS中,这种有限的子查询(据我所知)也不会破坏交易。

您还可以看到,物理计划表明Catalyst Optimizer已将您的IN子查询优化/转换为JOIN,这对于较大的数据集而言是典型的性能改进。

因此,发生了将较小的表“广播”到执行者的工作节点的情况,从而也提高了性能。您可能不需要为广播设置任何限制,但是可以根据我的观察明确地设置此限制,但是可以接受的是,这不是必需的。