Apache spark 为什么spark仍然比mysql慢?

Apache spark 为什么spark仍然比mysql慢?,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我正在尝试使用ApacheSpark和数据源MySQL。我有一个集群,有1个主节点和1个从节点,都有8 GB ram和2个内核。我正在使用spark shell向spark提交SQL查询,该表有这么多行。我正在那张桌子上进行分组。MySQL所用的时间是5.2秒,在执行查询时使用spark的时间是21秒。为什么会这样 我还设置了一些配置,如分区列、上限、下限和numofPartitions,但仍然没有更改 我也尝试过使用1,2,4个内核执行查询,但是spark所用的时间是相同的21s 这个问题是因

我正在尝试使用ApacheSpark和数据源MySQL。我有一个集群,有1个主节点和1个从节点,都有8 GB ram和2个内核。我正在使用spark shell向spark提交SQL查询,该表有这么多行。我正在那张桌子上进行分组。MySQL所用的时间是5.2秒,在执行查询时使用spark的时间是21秒。为什么会这样

我还设置了一些配置,如分区列、上限、下限和numofPartitions,但仍然没有更改

我也尝试过使用1,2,4个内核执行查询,但是spark所用的时间是相同的21s

这个问题是因为我的MySQL数据库在一台机器上 所有spark节点都试图在这台机器上查询数据

有人能帮我解决这个问题吗

我试图查询的数据库有一个名为demo_call_stats的表,该表是:

val jdbcDF = spark.read.format("jdbc").options( Map("url" ->  "jdbc:mysql://192.168.0.31:3306/cmanalytics?user=root&password=","zeroDateTimeBehaviour"->"convertToNull", "dbtable" -> "cmanalytics.demo_call_stats", "fetchSize" -> "10000", "partitionColumn" -> "newpartition", "lowerBound" -> "0", "upperBound" -> "4", "numPartitions" -> "4")).load()

jdbcDF.createOrReplaceTempView("call_stats")

val sqlDF = sql("select Count(*), classification_id from call_stats where campaign_id = 77 group by classification_id")

sqlDF.show()
任何帮助都将不胜感激


谢谢

这里有几件事你应该了解:

不管你可能听说过什么,Spark并没有“比MySQL快”,只是因为这种通用性并不意味着什么。 对于某些查询,Spark比MySQL快,对于其他查询,MySQL比Spark快。 一般来说,MySQL是一个关系数据库,这意味着它被认为是服务于 作为应用程序的后端。它经过优化,只要记录被编入索引,就可以有效地访问记录

在考虑数据库时,我喜欢将其视为一个图书馆,由一名图书管理员帮助您获取所需书籍 (我说的是一个非常古老的学校图书馆,没有任何计算机来帮助图书管理员)

如果你问你的图书管理员: “我想知道你们有多少本关于地缘政治的书”, 图书管理员可以到地缘政治书架上数一数书架上的书的数量

如果你问你的图书管理员: “我想知道你有多少本书至少有500页”, 图书馆员必须查看图书馆里的每一本书才能回答你的问题。 在SQL中,这称为完整表扫描。 当然,您可以让多个图书管理员(处理器)处理查询,以加快速度, 但是在你的图书馆(计算机)里,你不能有超过几个(比如说多达16个)

现在,Spark被设计用来处理大量的数据,即非常大的库 它们无法容纳一栋建筑,即使能容纳,它们的数量也会如此之多 即使是16名图书管理员也要花上几天的时间来查看它们,才能回答您的第二个问题

Spark比MySQL更快的原因是:如果你把书放在几栋楼里, 每栋建筑可以有16名图书管理员为您解答问题。 您还可以处理大量的书籍

此外,由于Spark主要回答第二类问题,而不是像“请给我带来奥斯卡·王尔德的《道林·格雷的画像》”这样的问题,这意味着Spark不在乎,至少在默认情况下,以任何特定的方式对你的书进行排序。 这意味着,如果你想找到有火花的那本书,你的图书管理员将 通过整个图书馆找到它

当然,Spark使用许多其他类型的优化来更高效地执行某些查询, 但是索引不是其中之一(如果您熟悉mySQL中主键的概念,那么Spark中就没有这样的东西)。 其他优化包括存储格式,如拼花和ORC,允许您只读取有用的列 回答您的问题,并进行压缩(例如Snappy),目的是增加您可以容纳的书籍数量 在你的图书馆里,不用推墙

我希望这个比喻对你有所帮助,但请记住,这只是一个比喻 并不完全符合现实

现在,回到问题的具体细节:

假设
campaign\u id
是您的主键,或者您在该列上创建了一个索引,MySQL将只有 要读取
活动id=77的行
。 另一方面,Spark必须请求mySQL将该表中的所有行发送给Spark。 如果Spark很聪明,它只会要求使用
campaign\u id=77
,也许它会向mySQL发送多个查询以并行获取范围。 但这意味着MySQL可以读取和聚合的所有数据都必须序列化,发送到Spark,然后由Spark聚合。 我希望你明白为什么这需要更长的时间

如果您想让Spark比MySQL更快地回答您的查询,那么您应该尝试用其他类似的格式复制表

// replace this line :
// jdbcDF.createOrReplaceTempView("call_stats")
// with :
jdbcDF.write.format("orc").saveAsTable("call_stats")
您可以尝试的另一件事是像这样缓存数据:

jdbcDF.cache().createOrReplaceTempView("call_stats")
缓存不会给第一个查询带来任何改进,因为它会在执行时缓存数据,但是如果继续查询同一个视图,可能会更快。 但正如我上面解释的,这并不意味着Spark在所有方面都比mySQL快

对于小数据和本地部署,您还可以通过更改此配置来获得性能改进 参数:
spark.sql.shuffle.partitions=4
,默认值为200


希望这有帮助。

如果数据不在RAM中,Spark需要在执行计算之前提取数据。因此,网络IO可能是一个瓶颈。既然我不确定你是如何衡量你的查询性能,也不知道你的数据分布,也不知道你的数据分布,我们在这里帮不上忙。请考虑共享一些代码和一些关于你的数据的信息。您可能得不到具体的解决方案,但也许我可以用一些指针来帮助您。@eliasah我正在使用spark web UI测量查询性能。另外,1个从机和2个内核甚至不是一个好的设置。宁愿有一个