hive的一些优化配置
hive可以通过如下三种方式进行设置配置参数:
- 配置文件中设置。可以设置在$HIVE_HOME/conf/hive-site.xml中,参数全局有效。
- 命令行参数设置。可以通过beeline -u jdbc:hive2://host:10000 -hiveconf key=value设置,参数仅对本次连接有效。
- 会话参数设置。可以在本次连接客户端中通过set命令来设置,参数仅对本次连接有效。
以上三种参数设置方式优先级如下:会话参数设置>命令行参数设置>配置文件设置。
1. 本地模式运行
“hive.exec.mode.local.auto”参数设置Hive是否自动开启本地模式,默认为false。默认Hive执行SQL语句时,无论SQL查询数据量多少,都会转换成分布式MapReduce执行,但对于一些测试场景或者Hive处理的数据量非常小情况下,如果还是采用分布式执行,反而会导致任务执行总时间很长。
这时可以设置“hive.exec.mode.local.auto”参数为true,让Hive根据查询数据量来自动决定执行SQL是否使用本地模式,如果数据量不大,Hive查询就可以直接在HiveServer2本机执行Local MapReduce,而不在集群上分布式运行MapReduce。
开启Hive本地模式后,Hive自动判断是否本地模式执行SQL的相关参数如下:
- hive.exec.mode.local.auto.inputbytes.max
该参数设置Hive执行本地模式MR最大输入的数据量,默认值为123217728,即128M。输入数据量小于该值时,会默认本地模式执行MR。
- hive.exec.mode.local .auto.input.files.max
该参数设置hive执行本地模式MR最大输入文件个数,也就是map端的并行度,该值默认为4,即:如果map task小于4并且输入数据量小于hive.exec.mode.local.auto.inputbytes.max时执行本地模式。
2. Fetch抓取
“hive.fetch.task.conversion”参数设置一些SELECT查询是否转换为单个FETCH任务,而最小化延迟。Hive SQL 启用 MapReduce Job 是会消耗系统开销,Hive 中对某些情况的查询可以不必使用 MapReduce 计算,如:对于简单的不需要聚合的类似 select col from table limit n语句,不需要起 MapReduce job,直接通过 Fetch task 获取表目录下的数据然后输出到控制台。
hive.fetch.task.conversion参数可以设置为:none、minimal、more三个值,默认为more,建议采用默认值即可。三者解释如下:
- hive.fetch.task.conversion设置为none
禁用fetch任务转换。所有查询将按照常规方式执行,而不尝试优化为单个FETCH任务。
- hive.fetch.task.conversion设置为minimal
仅在满足特定条件的情况下,转换为FETCH任务。这些条件包括:select *查询、过滤分区列、使用limit语句。
- hive.fetch.task.conversion设置为more
在更多情况下转换为FETCH任务,这些条件包括select查询、过滤查询、limit、虚拟列查询等。相较于minimal,more允许更广泛的查询类型转换为FETCH任务。
如下,本身select * 查询不会之心MR 任务,如果将hive.fetch.task.conversion设置为none后会执行MR任务。
0: jdbc:hive2://hadoop101:10000> set hive.fetch.task.conversion;
+----------------------------------+
| set |
+----------------------------------+
| hive.fetch.task.conversion=more |
+----------------------------------+
1 row selected (0.009 seconds)
0: jdbc:hive2://hadoop101:10000> select * from emp limit 10;0: jdbc:hive2://hadoop101:10000> set hive.fetch.task.conversion = none;0: jdbc:hive2://hadoop101:10000> select * from emp limit 10;
第二次执行会生成MR任务,查询变慢
3. 开启谓词下推
“hive.optimize.ppd”参数表示是否开启Hive谓词下推(predicate pushdown),默认为true,表示开启,建议采用默认值即可。谓词下推表示尽量将SQL中的where条件前移,减少后续计算步骤数据量。
4. 开启向量化执行
“hive.vectorized.execution.enabled”参数表示是否开启Hive向量化执行,默认为true,表示开启,建议采用默认值即可。相当于从原来的map逐行处理数据变成批量处理数据,从处理一行到一次性处理多行,减少cpu指令和cpu上下文切换提高效率。
当对一些SQL语句执行explain时可以看到执行计划中“Execution mode: vectorized”,表示开启了向量化执行。
5. 开启CBO优化
在Hive中执行多表Join时,Hive默认开启了CBO(Cost Based Optimization)优化,系统会自动根据表的统计信息,例如数据量、文件数等,选出合适执行计划提高多表Join的效率,Hive需要先收集表的统计信息后才能使CBO正确的优化。CBO优化器会基于统计信息和查询条件,尽可能地使join顺序达到更优,但是也可能存在特殊情况导致join顺序调整不准确。例如数据存在倾斜,以及查询条件值在表中不存在等场景,可能调整出非优化的join顺序。
CBO优化参数为“hive.cbo.enable”,默认为true,建议保持默认值即可。
6. 开启Job并行执行
“hive.exec.parallel”参数表示是否并行执行Jobs,默认为false,表示不开启,建议设置为true。Hive SQL 在底层会转换成一个或者多个Stage,这些Stage可能对应一个MapRedcue任务,在复杂SQL中,转换成的多个Stage之间可能没有依赖关系,对应的MapReduce Job并不按照顺序依次执行,这是就可以将这些Stage并行执行提高效率。该参数设置的并行执行指的就是并行运行Stage。
还可通过设置“hive.exec.parallel.thread.number”参数来指定并行执行Stage的并行度,默认为8。在资源充足的时候hive.exec.parallel会让那些存在并发job的sql运行得更快,但同时消耗更多的资源。
7. 开启Hive严格模式
Hive严格模式主要涉及三个参数:“hive.strict.checks.no.partition.filter”、“hive.strict.checks.orderby.no.limit ”、“hive.strict.checks.cartesian.product ”。
1) hive.strict.checks.no.partition.filter
Hive分区表的设计目的是通过分区剪裁来减少扫描的数据量,从而提高查询性能,如果在查询中没有指定分区过滤条件,Hive将扫描整个表的所有分区,可能会导致查询性能下降,该参数就是设置当查询没有指定分区过滤条件是否允许SQL执行。
该参数设置为true时,如果对分区表的查询中没有包含分区过滤条件,Hive将会禁止该查询的执行;设置为 false 时,Hive不会对缺少分区过滤条件的查询做出限制,默认为false,建议设置为true。
2) hive.strict.checks.orderby.no.limit
在Hive中ORDER BY子句用于对查询结果进行排序,如果数据集非常大,没有 LIMIT 子句的 ORDER BY 查询可能会导致非常高的内存和计算开销,因为Hive需要对整个数据集进行排序。该参数用于设置是否允许order by 后没有limit语句的SQL执行。
当该参数设置为true时,如果在ORDER BY查询中没有包含LIMIT子句,Hive将会禁止该查询的执行;当该参数设置为false时,Hive允许执行没有LIMIT子句的ORDER BY查询。该值默认为false,建议设置为true。
3) hive.strict.checks.cartesian.product
Hive中笛卡尔积操作会导致非常高的计算和存储开销,尤其是当参与连接的表数据量很大时,会导致性能问题和资源过载。该参数就是设置在Hive中是否允许笛卡尔积操作。
当该参数设置为true时,Hive将禁止执行笛卡尔积(交叉连接,cross join)查询;当该参数设置为false时,Hive允许执行笛卡尔积查询。默认为false,建议设置为true。
8. 设置合理并行度
Hive SQL底层转换成MapReduce任务,这里说的设置并行度主要是针对SQL转换成的MapReduce任务Map端和Reduce端并行度进行设置。
8.1 Map Tasks并行度设置
Map Task并行度就是Map Task个数,默认由输入文件的切片数决定,相关参数如下:
#MapReduce 任务中,输入文件的最小切分大小,默认值为1byte。
set mapred.min.split.size;#MapReduce 任务中,输入文件的最大切分大小,默认值为256000000byte,约256M。
set mapred.max.split.size;
在使用Hql处理数据时,读取的数据数据量如果很大,默认转换成的MR任务会按照“mapred.max.split.size”进行文件切分,切分的个数就是MapTask的个数。如果处理中涉及到计算复杂的操作,可以考虑将“mapred.max.split.size”参数调小,以增大MapTask的并行度,可以加快数据处理速度。
注意:绝大多数情况下不需要我们手动调整Map Task个数,按照输入文件的切片数据决定即可(切片不会跨文件,也就是说如果有2个小文件会对应到2个split切片上)。
如下案例中,表中的数据量为976M,进行count查询时,可以通过YarnWebUI查看对应的MapTask个数。
#查询切片默认参数
set mapred.min.split.size;
+--------------------------+
| set |
+--------------------------+
| mapred.min.split.size=1 |
+--------------------------+set mapred.max.split.size;
+----------------------------------+
| set |
+----------------------------------+
| mapred.max.split.size=256000000 |
+----------------------------------+#默认不设置任何参数执行如下SQL
select count(*) from temp ;
以上转换成的MapReduce 任务map task个数为(976M/256M≈3.8):
可以看到Map Task个数为4。
8.2 Reduce Task并行度设置
进行并行度调节时绝大多数调节的主要是Reduce Task个数,可以通过设置“mapred.reduce.tasks”参数进行Reduce Task个数设置,该值默认为-1 ,表示Hive 能够根据具体作业的特征和集群资源的情况,动态地决定适当的 reduce 任务数,从而优化性能和资源利用。在Hive中计算Reduce Task个数的公式如下:
reduce_task_num = min(hive.exec.reducers.max,总输入数据量/hive.exec.reducers.bytes.per.reducer)
- hive.exec.reducers.max:reduce短可设置的最大并行度,默认1009。
- hive.exec.reducers.bytes.per.reducer:单个reduce task处理的数据量,默认值为256000000,约等于256M。
用户也可以设置该参数为正值来设置Reduce Task个数。在本地模式中,改参数默认值为1。
注意:执行的SQL不能是只有一个聚合结果的SQL,否则看不到Reduce多并行度处理数据的效果。此外,reduce个数并不是越多越好,过多的启动和初始化reduce也会消耗时间和资源;另外过多的reduce会生成很多个结果文件,同样产生了小文件的问题。
9. Map-Side 预聚合
在Hive中Map-Side预聚合是一种优化技术,可以减少Shuffle阶段的数据量和网络传输成本。HQL转换成MapReduce任务执行,Map阶段的输出会被shuffle并根据key进行排序,然后发送给Reduce阶段进行进一步处理,对于聚合操作场景,Map-side预聚合允许在Map任务结束之前对数据进行局部聚合,可以显著减少Reduce阶段需要处理的数据量。
Map-Side预聚合相关参数如下:
- hive.map.aggr
该参数表示在group by语句中是否开启map端预聚合,默认为true,建议设为true。
- hive.map.aggr.hash.min.reduction
该参数控制聚合查询时表是否适合执行Map-side预聚合,默认值为0.99。判断方式:首先对若干条数据(hive.groupby.mapaggr.checkinterval设置)进行map-side聚合,聚合后的结果条数与聚合前的条数比例如果小于该值,则认为表聚合查询适合进行map-side聚合,否则不适合。建议设置为默认值。
- hive.groupby.mapaggr.checkinterval
该参数是用于判断源表是否适合map端预聚合的条数,默认值100000。建议设置为默认值。
- hive.map.aggr.hash.force.flush.memory.threshold
该参数表示Map-Side聚合使用到的hash表占用map task 堆内存最大比例,默认值0.9,超过该值,则会将hash表强制刷写磁盘。
10. 建表指定分区和压缩格式
Hive在做Select查询时,一般会扫描整个表内容,会消耗较多时间去扫描不关注的数据。此时可根据业务需求及其查询维度,建立合理的表分区,从而提高查询效率。
同时为了使数据在传输上更小,处理起来更快,可以对Hive数据进行压缩。
- 在实际开发中,Hive表的数据存储格式一般选择 orc或者parquet,压缩方式一般选择lzo/snappy。所以常见的存储格式及压缩组合为orc+lzo、orc+snappy、parquet+lzo、parquet+snappy。
- 如果使用orc存储格式表,建表时指定压缩格式时tabproperties参数为“orc.compress”;如果使用parquet存储格式表,建表时指定压缩格式时tabproperties参数为“parquet.compression”
11. Hive小文件优化
小文件通常指的是比HDFS Block块要小很多的文件,在Hive中存在小文件的主要原因如下:
- 数据源本身存在大量小文件,这些小文件可能是多次向Hive表插入/导入数据产生。
- HQL执行过程和写出结果产生大量小文件,由于Reduce Task数量多导致结果小文件多。
Hive中存在大量小文件除了会导致HDFS中元数据大占用内存多之外,还会导致在处理数据过程中每个小文件对应一个Map Task ,导致非常多的Map Task运行且处理的数据量小,影响性能和浪费资源。
解决Hive小文件问题可以考虑以下几个方面入手。
11.1 设置Map和Reduce端文件合并
Map和Reduce端文件合并涉及到的参数如下:
- hive.input.format
该参数可以将多个小文件合并成一个文件被一个Map Task处理。默认值为org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,即Map端合并小文件。该参数无需额外设置。
- hive.merge.mapfiles
该参数针对map only任务输出的小文件进行合并,默认值为true,如果存在小文件情况下,建议设置为true。
- hive.merge.mapredfiles
该参数设置为true时会在MapReduce任务执行完成后,对输出的小文件进行合并。默认值为false,如果存在小文件情况下,建议设置为true。
- hive.merge.size.per.task
该参数表示合并后文件大小上限,默认值为256000000byte,约256M。建议设置为默认值即可。
- hive.merge.smallfiles.avgsize
该参数表示触发小文件合并的文件阈值,如果MR任务输出的所有文件平均值小于该值,Hive将启动一个额外的map-reduce作业,将输出文件合并为更大的文件。默认值为16000000byte,约16M。建议设置为默认值即可。
注意:只会在一个任务内有效;
11.2 insert overwrite 合并文件
如果一张表中小文件特别多,可以通过insert overwrite方式读取该表数据并重新插入覆盖到该表,这样会将多个小文件合并成一个大文件。
11.3 使用HDFS CONCAT命令合并小文件
hdfs 中concat命令可以合并多个小文件,使用命令如下:
hadoop fs -concat target_file source_file1 source_file2 ... ...
以上命令参数解释如下:
- target_file:将多个文件合并到的文件名称。
- source_filex:多个小文件名称,合并后文件自动删除。