1.Fetch抓取
Fetch 抓取是指,Hive 中对某些情况的查询可以不必使用 MapReduce 计算。
启用 MapReduce Job 是会消耗系统开销的。对于这个问题,从 Hive0.10.0 版本开始,对于简单的不需要聚合的类似
select <col> from <table> limit n
语句,不需要起 MapReduce job,直接通过 Fetch task 获取数据。
比如:select * from user_table;
在这种情况下,Hive 可以简单地读取 user_table 对应的存储目录下的文件,然后输出查询结果到控制台。
在 hive-default.xml.template
文件中hive.fetch.task.conversion
默认是 more,老版本 hive 默认是 minimal,该属性修改为 more 以后,在全局查找、字段查找、limit 查找等都不走MapReduce。
default> use default
[2022-10-11 09:40:09] 在 268 ms 内完成
default> set hive.fetch.task.conversion=more
[2022-10-11 09:40:09] 在 19 ms 内完成
default> select *
from dwd_farm_n.dim_farm_organization_zhuboshi
[2022-10-11 09:40:09] 在 425 ms (execution: 143 ms, fetching: 282 ms) 内检索到从 1 开始的 356 行
default> set hive.fetch.task.conversion=none
[2022-10-11 09:40:45] 在 20 ms 内完成
default> select *
from dwd_farm_n.dim_farm_organization_zhuboshi
[2022-10-11 09:41:11] 在 13 s 478 ms (execution: 12 s 891 ms, fetching: 587 ms) 内检索到从 1 开始的 356 行
可以看到相差还是不少的,一个是425ms一个是13s!
2.Hive本地模式运行
假设你正在运行一些复杂的 Hive 查询,我们都知道这会在后台触发 MapReduce 作业并为你提供输出。如果 Hive 中的数据比较大,这种方法比较有效,但如果 Hive 表中的数据比较少,这样会有一些问题。出现此问题的主要原因是 MapReduce 作业被触发,它是在服务器/集群上触发,因此每次运行查询时,它都会上传到服务器并在那里启动 MapReduce,然后输出。因此,为查询触发执行任务的时间消耗可能会比实际作业的执行时间要多的多。
Hive 可以通过本地模式在单台机器上处理所有的任务。对于本地模式,如果你的查询启动的 MapReduce 作业少于4个 Mapper,那么 MapReduce 作业将在本地运行,这样可以在更短的时间内输出查询结果。
启用方式
set hive.exec.mode.local.auto=true;(默认为false)
一般需要满足如下三个配置条件,才能在本地模式下运行 Hive 查询:
参数 | 默认值 | 描述 |
---|---|---|
hive.exec.mode.local.auto | false | 让Hive确定是否自动启动本地模式运行 |
hive.exec.mode.local.auto.inputbytes.max | 134217728(128MB) | 当第一个参数为true时,输入字节小于此值时才能启动本地模式 |
hive.exec.mode.local.auto.input.files.max | 4 | 当一个参数为true时,任务个数小于此值时才能启动本地模式 |
default> set hive.exec.mode.local.auto=true
[2022-10-11 09:56:10] 在 28 ms 内完成
default> set hive.exec.mode.local.auto.inputbytes.max=50000000
[2022-10-11 09:56:10] 在 56 ms 内完成
default> set hive.exec.mode.local.auto.input.files.max=5
[2022-10-11 09:56:10] 在 19 ms 内完成
default> select *
from dwd_farm_n.dim_farm_organization_zhuboshi
[2022-10-11 09:56:11] 在 359 ms (execution: 143 ms, fetching: 216 ms) 内检索到从 1 开始的 356 行
可以看到运行时间缩减到了400ms以内
注意:当执行数据量较大的查询时,强烈不建议开启本地模式,会比集群模式慢很多或者压根跑不出来,这个需要使用者自己判断数据量大小情况
3.严格模式
严格模式 Hive提供了一个严格模式,可以防止用户执行“高危”的查询。
通过设置属性hive.mapred.mode值为默认是非严格模式nonstrict 。开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。
<property>
<name>hive.mapred.mode</name>
<value>strict</value>
<description>
The mode in which the Hive operations are being performed.
In strict mode, some risky queries are not allowed to run. They include:
Cartesian Product.
No partition being picked up for a query.
Comparing bigints and strings.
Comparing bigints and doubles.
Orderby without limit.
</description>
</property>
①对于分区表,用户不允许扫描所有分区,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
②对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
③限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。
4.Map数
通常情况下,作业会通过input的目录产生一个或者多个map任务。 主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M,可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改);
举例: 一个大文件: 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数。 多个小文件:假设input目录下有3个文件a,b,c大小分别为10m,20m,150m,那么hadoop会分隔成4个块(10m,20m,128m,22m),从而产生4个map数。即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
是不是map数越多越好?
答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
是不是保证每个map处理接近128m的文件块,就高枕无忧了? 答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。 针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;
如何适当的增加map数
当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。 控制map数量需要遵循两个原则:使大数据量利用合适的map数;使单个map任务处理合适的数据量;
5.Reduce数
调整reduce个数方法一
每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256123456
每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=1009
计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
调整reduce个数方法二
在hadoop的mapred-default.xml文件中修改
设置每个job的Reduce个数
set mapreduce.job.reduces = 15;
reduce个数并不是越多越好?
过多的启动和初始化reduce也会消耗时间和资源; 另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题; 在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;