首页 > 解决方案 > 查询需要很长时间'选择'什么

问题描述

我有一个查询,我在节俭中运行了很长时间。我在具有 500k 行的表的单个分区上运行它。

查询如下所示:

select col0 from <table> where partition=<partition> and <col1>=<val>

我做到了col1 != val,所以查询返回 0 行。

此查询大约需要 30 秒(如果我使用,则为一分钟select *)。

当我运行完全相同的查询但select count(col0)需要 2 秒时。

什么可能导致查询需要很长时间select col而不是select count(col)

这是解释的查询

explain select col0 from table where `partition` = partition and col=val;

*Project [col0#607]
+- *Filter (isnotnull(col1#607) && (col1#607 = aaaa))
+- *FileScan parquet
table[col1#607,partition#611]
批处理:true,
格式:Parquet,
位置:PrunedInMemoryFileIndex[...,
PartitionCount:23,
PartitionFilters:[isnotnull(partition#611),
(cast(partition#611 as int) = partition_name)],
PushedFilters:[IsNotNull(col1),
EqualTo(col1,aaaa) ],
ReadSchema:结构

explain select count(col0) from table where `partition` = partition and col=val;

*HashAggregate(keys=[], functions=[count(col0#625)])
+- Exchange SinglePartition
+- *HashAggregate(keys=[], functions=[partial_count(col0#625)])
+- *Project [col0 #625]
+- *Filter (isnotnull(col1#625) && (col1#625 = aaaa))
+- *FileScan parquet
table[col1#625,partition#629] 批处理:true,
格式:Parquet,
位置:PrunedInMemoryFileIndex[ ...,
PartitionCount: 23,
PartitionFilters: [isnotnull(partition#629),
(cast(partition#629 as int) = partition_name)],
PushedFilters: [IsNotNull(col1),
EqualTo(col1,aaaa)],
读取架构:结构

据我所知,过程完全一样,只是count查询有更多的步骤。那么它为什么快 15 倍呢?

编辑

我在日志中发现了这个有趣的块:

与计数

18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 启动任务 0.0(TID 8092,ip-123456,执行器 36,分区 0,RACK_LOCAL,5521 字节)
28/06 11:42:55 INFO TaskSetManager :在阶段 2509.0 中启动任务 1.0(TID 8093,ip-123456,执行程序 35,分区 1,RACK_LOCAL,5521 字节)
18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 中启动任务 2.0(TID 8094,ip -123456,执行程序 36,分区 2,RACK_LOCAL,5521 字节)
18/06/28 11:42:55 信息 TaskSetManager:在阶段 2509.0 中启动任务 3.0(TID 8095,ip-123456,执行程序 35,分区 3,RACK_LOCAL,5521字节)
18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 启动任务 4.0(TID 8096,ip-123456,执行程序 36,分区 4,RACK_LOCAL,5521 字节)
18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 启动任务 5.0(TID 8097,ip-123456,执行程序 35,分区 5,RACK_LOCAL,5521 字节)
28/06/18 11:42:55 INFO TaskSetManager :在阶段 2509.0 中启动任务 6.0(TID 8098,ip-123456,执行程序 36,分区 6,RACK_LOCAL,5521 字节)
18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 中启动任务 7.0(TID 8099,ip -123456,执行程序 35,分区 7,RACK_LOCAL,5521 字节)
18/06/28 11:42:55 信息 TaskSetManager:在阶段 2509.0 启动任务 8.0(TID 8100,ip-123456,执行程序 36,分区 8,RACK_LOCAL,5521字节)
18/06/28 11:42:55 INFO TaskSetManager:在阶段 2509.0 启动任务 9.0(TID 8101,ip-123456,执行程序 35,分区 9,RACK_LOCAL,5521 字节)

18/06/28 11:45:32 INFO TaskSetManager:在阶段 2512.0 中启动任务 0.0(TID 8136,ip-10-117-49-97.eu-west-1.compute.internal,执行程序 37,分区 1,RACK_LOCAL , 5532 字节)
18/06/28 11:45:32 INFO BlockManagerInfo:在内存中添加了广播_2352_piece0 ip-10-117-49-97.eu-west-1.compute.internal:40489(大小:12.6 KB,免费: 11.6 GB)
18/06/28 11:45:32 INFO TaskSetManager: 在 ip-10-117-49-97.eu-west-1.compute.internal 的 667 毫秒内完成阶段 2512.0 (TID 8136) 中的任务 0.0 (执行者 37)(1/1)
18/06/28 11:45:32 INFO YarnScheduler:从池 18/06/28 11:45:32 中删除了 TaskSet 2512.0,其任务已全部完成,
INFO DAGScheduler:ResultStage 2512( OperationManager.java:220 处的 getNextRowSet)在 0.668 秒内完成
28 年 6 月 18 日 11:45:32 信息 DAGScheduler:作业 2293 完成:OperationManager.java:220 处的 getNextRowSet,耗时 0.671740 秒
18/06/28 11:45:32 信息 SparkContext:开始作业:OperationManager.java 处的 getNextRowSet: 220
18/06/28 11:45:32 INFO DAGScheduler:得到作业 2294 (getNextRowSet at OperationManager.java:220) 1 输出分区
18/06/28 11:45:32 INFO DAGScheduler:最后阶段:ResultStage 2513 (getNextRowSet在 OperationManager.java:220)
18/06/28 11:45:32 信息 DAGScheduler:最后阶段的父母:List()
18/06/28 11:45:32 信息 DAGScheduler:失踪父母:List()
18/06 /28 11:45:32 INFO DAGScheduler: 提交 ResultStage 2513 (MapPartitionsRDD[312] at run at AccessController.java:0),没有丢失的父母
18/06/28 11:45:32 INFO MemoryStore:块 broadcast_2353 存储为内存中的值(估计大小 66.6 KB,空闲 12.1 GB)
18/06/28 11:45:32 INFO MemoryStore:块 broadcast_2353_piece0 存储为内存中的字节(估计大小 12.6 KB,免费 12.1 GB)
18/06/28 11:45:32 INFO BlockManagerInfo:在内存中添加了广播_2353_piece0 10.117.48.68:41493(大小:12.6 KB,免费:12.1 GB)
18/06/28 11 :45:32 INFO SparkContext:从 DAGScheduler.scala:1047 18/06/28 11:45:32 的广播创建广播 2353
信息 DAGScheduler:从 ResultStage 2513 提交 1 个丢失的任务(MapPartitionsRDD [312] 在 AccessController.java 运行时: 0)(前 15 个任务用于分区
Vector(2))18/06/28 11:45:32 INFO YarnScheduler:添加任务集 2513.0 和 1 个任务
28 年 6 月 18 日 11:45:32 信息 TaskSetManager:在阶段 2513.0 中启动任务 0.0(TID 8137,ip-10-117-49-97.eu-west-1.compute.internal,执行程序 37,分区 2,RACK_LOCAL , 5532 字节)
18/06/28 11:45:33 INFO BlockManagerInfo:在内存中添加了广播_2353_piece0 ip-10-117-49-97.eu-west-1.compute.internal:40489(大小:12.6 KB,免费: 11.6 GB)
18/06/28 11:45:38 INFO TaskSetManager: 在 ip-10-117-49-97.eu-west-1.compute.internal 的 5238 毫秒内完成阶段 2513.0 (TID 8137) 中的任务 0.0 (执行者 37)(1/1)
18/06/28 11:45:38 INFO YarnScheduler:从池 18/06/28 11:45:38 中删除了 TaskSet 2513.0,其任务已全部完成,
INFO DAGScheduler:ResultStage 2513( OperationManager.java:220 处的 getNextRowSet)在 5.238 秒内完成
28 年 6 月 18 日 11:45:38 信息 DAGScheduler:作业 2294 完成:OperationManager.java:220 的 getNextRowSet,耗时 5.242084 秒
28 年 6 月 18 日 11:45:38 信息 SparkContext:开始作业:OperationManager.java 的 getNextRowSet: 220
18/06/28 11:45:38 INFO DAGScheduler:得到作业 2295(在 OperationManager.java:220 上的 getNextRowSet),带有 1 个输出分区
18/06/28 11:45:38 INFO DAGScheduler:最后阶段:ResultStage 2514(getNextRowSet在 OperationManager.java:220)
18/06/28 11:45:38 信息 DAGScheduler:最后阶段的父母:List()
18/06/28 11:45:38 信息 DAGScheduler:失踪父母:List()
18/06 /28 11:45:38 INFO DAGScheduler: 提交 ResultStage 2514 (MapPartitionsRDD[312] at run at AccessController.java:0), 没有丢失的父母
18/06/28 11:45:38 INFO MemoryStore:块 broadcast_2354 作为值存储在内存中(估计大小 66.6 KB,空闲 12.1 GB)
18/06/28 11:45:38 INFO MemoryStore:块 broadcast_2354_piece0 作为字节存储在内存中(估计大小 12.6 KB,免费 12.1 GB)
18/06/28 11:45:38 INFO BlockManagerInfo:在内存中添加了广播_2354_piece0 10.117.48.68:41493(大小:12.6 KB,免费:12.1 GB)
18/06/28 11 :45:38 INFO SparkContext:从 DAGScheduler.scala:1047 18/06/28 11:45:38 的广播创建广播 2354
信息 DAGScheduler:从 ResultStage 2514 提交 1 个丢失的任务(MapPartitionsRDD [312] 在 AccessController.java 运行时: 0)(前 15 个任务用于分区 Vector(3))

(即它重复这个块,看起来它顺序运行任务而不是像计数情况那样并行)

我也尝试过“order by”,它实际上使查询运行速度提高了 2


使用 spark 而不是 thrift 对相同数据运行相同的查询要快得多。

我在 aws emr-5.11.1 上运行节俭

蜂巢 2.3.2

火花 2.2.1

节俭 0.11.0

标签: apache-sparkhive

解决方案


发现了问题。我有这面旗帜

spark.sql.thriftServer.incrementalCollect=true

在节俭服务器中。它按顺序收集每个工作人员的输出,这就是造成如此巨大开销的原因。删除标志解决了这个问题。我猜它被优化为在做“计数”时不做顺序,因为它不一定有很多数据。


推荐阅读