子查询中的配置单元“limit”在完全查询后执行

rbl8hiat  于 2021-05-29  发布在  Hadoop
关注(0)|答案(2)|浏览(409)

我正在测试一个相当累人的程序 rlike 配置单元查询中的函数。我想我应该先测试一个子集,然后再将它应用到tb+的数据中。完整查询是:

create table proxy_parsed_clean as
select
  a.*,
  case 
    when domainname rlike '.*:443$' then 1
    else 0
  end as used_https
from proxy_parsed a;

由于数据太多,我编写了一个查询(表面上)将针对一个子集进行操作:

select
  case 
    when a.domainname rlike '.*:443$' then 1
    else 0
  end as used_https
from (select domainname from proxy_parsed limit 10) a;

然而,这似乎和第一个查询所用的时间一样长。与其将外部查询应用于子集,不如将case语句应用于整个数据集,然后进行限制。运行 explain 证实了我的怀疑(注意 limit 子句移到查询的末尾):

> explain select case when a.domainname rlike '.*:443$' then 1 else 0 end from (select domainname from proxy_parsed limit 10) a;

+---------------------------------------------------------------------------------------------------------------------+--+
|                                                       Explain                                                       |
+---------------------------------------------------------------------------------------------------------------------+--+
| STAGE DEPENDENCIES:                                                                                                 |
|   Stage-1 is a root stage                                                                                           |
|   Stage-0 depends on stages: Stage-1                                                                                |
|                                                                                                                     |
| STAGE PLANS:                                                                                                        |
|   Stage: Stage-1                                                                                                    |
|     Map Reduce                                                                                                      |
|       Map Operator Tree:                                                                                            |
|           TableScan                                                                                                 |
|             alias: proxy_parsed                                                                                     |
|             Statistics: Num rows: 157462377267 Data size: 6298495090688 Basic stats: COMPLETE Column stats: NONE    |
|             Select Operator                                                                                         |
|               expressions: domainname (type: varchar(40))                                                           |
|               outputColumnNames: _col0                                                                              |
|               Statistics: Num rows: 157462377267 Data size: 6298495090688 Basic stats: COMPLETE Column stats: NONE  |
|               Limit                                                                                                 |
|                 Number of rows: 10                                                                                  |
|                 Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                    |
|                 Reduce Output Operator                                                                              |
|                   sort order:                                                                                       |
|                   Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                  |
|                   TopN Hash Memory Usage: 0.1                                                                       |
|                   value expressions: _col0 (type: varchar(40))                                                      |
|       Reduce Operator Tree:                                                                                         |
|         Select Operator                                                                                             |
|           expressions: VALUE._col0 (type: varchar(40))                                                              |
|           outputColumnNames: _col0                                                                                  |
|           Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                          |
|           Limit                                                                                                     |
|             Number of rows: 10                                                                                      |
|             Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                        |
|             Select Operator                                                                                         |
|               expressions: CASE WHEN ((_col0 rlike '.*:443$')) THEN (1) ELSE (0) END (type: int)                    |
|               outputColumnNames: _col0                                                                              |
|               Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                      |
|               File Output Operator                                                                                  |
|                 compressed: false                                                                                   |
|                 Statistics: Num rows: 10 Data size: 400 Basic stats: COMPLETE Column stats: NONE                    |
|                 table:                                                                                              |
|                     input format: org.apache.hadoop.mapred.TextInputFormat                                          |
|                     output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat                       |
|                     serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe                                       |
|                                                                                                                     |
|   Stage: Stage-0                                                                                                    |
|     Fetch Operator                                                                                                  |
|       limit: -1                                                                                                     |
|       Processor Tree:                                                                                               |
|         ListSink                                                                                                    |
|                                                                                                                     |
+---------------------------------------------------------------------------------------------------------------------+--+

如果我只是想跑 select * from proxy_parsed limit 10; ,查询执行得非常快。有人能解释a)为什么查询没有在子集上执行,以及b)如何使它这样做吗?
我可以创建一个临时表,在其中选择10条记录,然后执行查询,但这似乎有些草率。另外,那之后我还要清理临时table。这种行为看起来像Hive虫,即 limit 在这种情况下,行为显然不像看上去那样。

yzckvree

yzckvree1#

这个 limitcase ,但在处理 case -它实际上被应用了两次。虽然这是巧合,但在本例中,limit的两个应用程序分别对应于内部查询和外部查询。
在查询计划中,您可以看到Map阶段只选择一个列(“ expressions: domainname )并将结果数减少到10个(从157462377267)。这与内部查询相对应。然后reduce阶段应用于案例(“ expressions: CASE WHEN ((_col0 rlike '.*:443$')) THEN (1) ELSE (0) END )并将行数减少到10,但是您可以看到,在这个阶段中,预期的输入行数已经是10。reduce阶段对应于外部查询。
限制应用两次的原因是分布式执行。因为在map阶段结束时,您希望最小化发送到reducer的数据量,所以在这里应用限制是有意义的。达到限制后,Map程序将不再处理任何输入。然而,这还不够,因为每个Map器可能产生多达10个结果,加起来是Map器数量的10倍,因此reduce阶段必须再次应用限制。由于这种机制,通常您应该直接应用限制,而不是仅为此目的创建子查询。
总而言之,在我的解释中,查询计划看起来不错 limit 在应该处理的地方处理。这回答了你的问题,为什么 limitcase . 遗憾的是,这并不能解释为什么要花这么多时间。
更新:请参阅ozw1z5rd关于为什么这个查询尽管使用了 limit . 它解释了使用子查询会导致mapreduce作业启动,而直接查询会避免这种情况。

yacmzcpb

yacmzcpb2#

请看这些例子:

hive> select case when d rlike '.*:443$' then 1 else 0 end as https from ( select d from domainname limit 5 ) a; 
Query ID = hduser_20160908161152_e0be6db7-f5ac-40ee-b7fb-50ad58ca7f2f
Total jobs = 1
Launching Job 1 out of 1
:
.
OK
0
0
1
1
0
Time taken: 28.263 seconds, Fetched: 5 row(s)

28秒后完成,Map缩小作业已启动。

hive> select case when d rlike '.*:443$' then 1 else 0 end as https from domainname limit 5; 
OK
0
0
1
1
0
Time taken: 0.162 seconds, Fetched: 5 row(s)

0.162秒,并且没有启动任何map reduce作业。
一旦您输入到子查询中,map reduce作业就开始选择您需要的行。
在mapreduce中,输入文件被拆分,并且对于每个拆分,都会启动一个Map器。每个Map器只需获取数据并对其进行转换,然后将其传递给组合器、分区器和缩减器。因为每个Map器都是自己工作的,所以无法知道处理了多少行。除非使用分区表或临时表,否则这将强制执行表扫描。如您所见,限制是在计划中的表扫描之后完成的:

From Map Operator Tree:
1st does a full table scan ( Statistics: Num rows: 157462377267 ) 
2nd the operator limit will take only the first 10 rows.
Reducers will get these only these 10 rows from the Mappers as you can see from the reduce operator tree ( Statistics: Num rows: 10  )

这工作很慢

select
  case 
    when a.domainname rlike '.*:443$' then 1
    else 0
  end as used_https
from (select domainname from proxy_parsed limit 10) a;

这工作很快

select
  case 
    when domainname rlike '.*:443$' then 1
    else 0
  end as used_https
from proxy_parsed limit 10;

还要注意limit返回随机列:here。

相关问题