Hive 优化

时间:2021-07-15
本文章向大家介绍Hive 优化,主要包括Hive 优化使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1. 架构优化

  Hive支持多种执行引擎,分别是 MapReduce、Tez、Spark、Flink。可以通过hivesite.xml文件中的hive.execution.engine属性控制。

矢量化查询执行:

  矢量化查询(要求执行引擎为Tez)执行通过一次批量执行1024行而不是每行一行来提 高扫描,

聚合,过滤器和连接等操作的性能,这个功能一显着缩短查询执行时间。

set hive.vectorized.execution.enabled = true;
-- 默认 false
set hive.vectorized.execution.reduce.enabled = true;
-- 默认 false

备注:要使用矢量化查询执行,必须用ORC格式存储数据

成本优化器:

  Hive的CBO是基于apache Calcite的,Hive的CBO通过查询成本(有analyze收集的统 计信息)会生成有效率的执行计划,

最终会减少执行的时间和资源的利用,使用CBO 的配置如下:

SET hive.cbo.enable=true; --从 v0.14.0默认
true
SET hive.compute.query.using.stats=true; -- 默认false
SET hive.stats.fetch.column.stats=true; -- 默认false
SET hive.stats.fetch.partition.stats=true; -- 默认true

  定期执行表(analyze)的分析,分析后的数据放在元数据库中。

分区表:

  对于一张比较大的表,将其设计成分区表可以提升查询的性能,对于一个特定分区的 查询,

只会加载对应分区路径的文件数据,所以执行速度会比较快。

  分区字段的选择是影响查询性能的重要因素,尽量避免层级较深的分区,这样会造成 太多的子文件夹。一些常见的分区字段可以是:

  • 日期或时间。如year、month、day或者hour,当表中存在时间或者日期字段时
  • 地理位置。如国家、省份、城市等
  • 业务逻辑。如部门、销售区域、客户等等

分桶表:

  与分区表类似,分桶表的组织方式是将HDFS上的文件分割成多个文件。

  分桶可以加快数据采样,也可以提升join的性能(join的字段是分桶字段),因为分桶可 以确保某个key对应的数据在一个特定的桶内(文件),

巧妙地选择分桶字段可以大幅 度提升join的性能。

  通常情况下,分桶字段可以选择经常用在过滤操作或者join操作的字段。

存储格式:

  存储格式一般需要根据业务进行选择,生产环境中绝大多数表都采用TextFile、 ORC、Parquet存储格式之一。

  TextFile是最简单的存储格式,它是纯文本记录,也是Hive的默认格式。其磁盘开销 大,查询效率低,更多的是作为跳板来使用。

RCFile、ORC、Parquet等格式的表都 不能由文件直接导入数据,必须由TextFile来做中转。

  Parquet和ORC都是Apache旗下的开源列式存储格式。列式存储比起传统的行式存 储更适合批量OLAP查询,并且也支持更好的压缩和编码。

选择Parquet的原因主要 是它支持Impala查询引擎,并且对update、delete和事务性操作需求很低。

压缩:

  压缩技术可以减少map与reduce之间的数据传输,从而可以提升查询性能,关于压 缩的配置可以在hive的命令行中或者hive-site.xml文件中进行配置。

SET hive.exec.compress.intermediate=true

关于压缩的编码器可以通过mapred-site.xml, hive-site.xml进行配置,也可以通过命 令行进行配置,如:

-- 中间结果压缩
SET
hive.intermediate.compression.codec=org.apache.hadoop.io.compr
ess.SnappyCodec ;
-- 输出结果压缩
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress.codec =
org.apache.hadoop.io.compress.SnappyCodc

2.参数优化:

本地模式:

  当Hive处理的数据量较小时,使用本地模式速度更快。

SET hive.exec.mode.local.auto=true; -- 默认 false
SET hive.exec.mode.local.auto.inputbytes.max=50000000;
SET hive.exec.mode.local.auto.input.files.max=5; -- 默认 4

一个作业只要满足下面的条件,会启用本地模式

  • 输入文件的大小小于 hive.exec.mode.local.auto.inputbytes.max 配置的大 小
  • map任务的数量小于 hive.exec.mode.local.auto.input.files.max 配置的 大小
  • reduce任务的数量是1或者0

严格模式:

  所谓严格模式,就是强制不允许用户执行3种有风险的HiveQL语句。

  • 查询分区表时不限定分区列的语句;
  • 两表join产生了笛卡尔积的语句;
  • 用order by来排序,但没有指定limit的语句。

要开启严格模式,需要将参数 hive.mapred.mode 设为strict(缺省值)。

该参数可以不在参数文件中定义,在执行SQL之前设置(set hive.mapred.mode=nostrict )

JVM重用:

  当执行轻量级作业,开启JVM重用会比较有效。

# 代表同一个MR job中顺序执行的5个task重复使用一个JVM,减少启动和关闭的开销
SET mapreduce.job.jvm.numtasks=5;

  这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直 到任务完成后才能释放。

如果某个“不平衡的”job中有某几个reduce task执行的时间 要比其他Reduce task消耗的时间多的多的话,

那么保留的插槽就会一直空闲着却无 法被其他的job使用,直到所有的task都结束了才会释放。

 并行执行:

Hive的查询通常会被转换成一系列的stage,这些stage之间并不是一直相互依赖的, 可以并行执行这些stage,通过下面的方式进行配置:

SET hive.exec.parallel=true; -- 默认false
SET hive.exec.parallel.thread.number=16; -- 默认8

  并行执行可以增加集群资源的利用率,如果集群的资源使用率已经很高了,那么并行 执行的效果不会很明显。

推测执行:

  启动备份任务,和原来的任务同时执行,处理同一份数据,先完成的作为最终结果。

set mapreduce.map.speculative=true
set mapreduce.reduce.speculative=true
set hive.mapred.reduce.tasks.speculative.execution=true

小文件合并:

 在map执行前合并小文件,减少map数:

# 缺省参数
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

在Map-Reduce的任务结束时合并小文件:

# 在 map-only 任务结束时合并小文件,默认true
SET hive.merge.mapfiles = true;
# 在 map-reduce 任务结束时合并小文件,默认false
SET hive.merge.mapredfiles = true;
# 合并文件的大小,默认256M
SET hive.merge.size.per.task = 268435456;
# 当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件
merge
SET hive.merge.smallfiles.avgsize = 16777216;

Fetch模式:

  Fetch模式是指Hive中对某些情况的查询可以不必使用MapReduce计算。select col1, col2 from tab ;

可以简单地读取表对应的存储目录下的文件,然后输出查询结果到控制台。

在开启 fetch模式之后,在全局查找、字段查找、limit查找等都不启动 MapReduce 。

# Default Value: minimal in Hive 0.10.0 through 0.13.1, more
in Hive 0.14.0 and later
hive.fetch.task.conversion=more

3.SQL优化

列裁剪和分区裁剪:

  列裁剪是在查询时只读取需要的列;分区裁剪就是只读取需要的分区。

  简单的说:select 中不要有多余的列,坚决避免 select * from tab; 查询分区表,不读多余的数据;

sort by 代替 order by:

  order by 是全局排序,只有一个reduce

  如果使用sort by,那么还是会视情况启动多个reducer进行排序,并且保证每个 reducer内局部有序。

  为了控制map端数据分配到reducer的key,往往还要配合 distribute by 一同使用。

  如果不加 distribute by 的话,map端数据就会随机分配到 reducer。

group by 代替 count(distinct):

  当要统计某一列的去重数时,如果数据量很大,count(distinct) 会非常慢。

原因与 order by类似,count(distinct)逻辑只会有很少的reducer来处理。

  

-- 原始SQL
select count(distinct uid)
from tab;
-- 优化后的SQL
select count(1)
from (select uid
from tab
group by uid) tmp;

即:在group by 外层统计数量

group by 配置调整:

  

原文地址:https://www.cnblogs.com/wanghzh/p/15015861.html