我正在尝试使用数据源MySQL的Apache spark。我有一个集群有1个主节点和1个从节点,并且都有8 GB ram和2个核心我正在使用spark-shell提交我的SQL查询以及那个 6402821 这一行的表。我正在组对该表执行操作。和 MySQL的时间是5.2秒并且当我执行查询时使用spark时间 21Secs 。为什么会这样?
我也设置了一些配置,例如 partitionColumn,upperBound,lowerBound和numofPartitions ,但仍然没有变化。
我也试过使用1,2,4核心执行查询,但是火花所用的时间是相同的 21Secs 。
发生这个问题是因为我的MySQL数据库是在一台机器上 所有的火花节点都试图在这台机器上查询数据吗?任何人都可以帮我解决这个问题吗?
我想要查询的数据库有一个名为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()
非常感谢任何帮助。
由于
答案 0 :(得分:14)
你应该在这里理解一些事情:
尽管你可能听说过,但Spark并不比“比MySQL更快”,只是因为这种普遍性并不意味着什么。 对于某些查询,Spark比MySQL更快,而对于其他查询,MySQL比Spark更快。 一般来说,MySQL是一个关系数据库,这意味着它已被设想为服务 作为应用程序的后端。只要将索引编入索引,它就会被优化为有效地访问记录。
在考虑数据库时,我喜欢把它们想象成一个带有一个图书管理员的图书馆来帮助你获得你想要的书籍 (我在这里谈论一个非常古老的学校图书馆,没有任何计算机来帮助图书管理员)。
如果你问你的图书管理员: “我想知道你有多少关于地缘政治的书籍, 图书管理员可以去地政政府的书架,并计算该书架上的书籍数量。
如果你问你的图书管理员: “我想知道你有多少本书至少有500页”, 图书馆员必须查看图书馆中的每本书来回答您的问题。 在SQL中,这称为全表扫描。 当然,您可以让几个图书管理员(处理器)处理查询以加快速度, 但是你的图书馆(计算机)内不能有多个(比方说多达16个)。
现在,Spark已被设计用于处理大量数据,即如此大的库 它们不适合单个建筑物,即使它确实如此,它们也会如此多 即使是16位图书管理员也需要花费数天的时间来回答他们所有人的问题。
使Spark比MySQL更快的原因是:如果你把书放在几栋楼里, 您可以有16位图书馆员每栋楼处理您的答案。 您还可以处理大量图书。
此外,由于Spark主要是为了回答第二类查询,而不是像“请带给我'多利安格雷的肖像',由奥斯卡·王尔德”这样的查询,这意味着Spark没有至少在默认情况下,要小心以任何特定方式对书籍进行排序。 这意味着,如果你想找到带有火花的特定书籍,你的图书馆员就会有 通过整个图书馆找到它。
当然,Spark使用许多其他类型的优化来更有效地执行某些查询, 但是索引不是其中之一(如果你熟悉mySQL中的主键概念,那么Spark中没有这样的东西)。 其他优化包括Parquet和ORC等存储格式,允许您只读取有用的列 回答您的问题和压缩(例如Snappy),旨在增加您可以容纳的书籍数量 在你的图书馆,而不必推墙。
我希望这个比喻可以帮助你,但请记住,这只是一个隐喻和 不完全适合现实。
现在,回到您的问题具体细节:
假设campaign_id
是您的主键,或者您在此列上创建了索引,MySQL将只有
读取campaign_id = 77
的行。
另一方面,Spark必须要求mySQL将该表中的所有行发送给Spark。
如果Spark很聪明,它只会要求campaign_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。
希望这有帮助。