show conf 值名
:查看配置项当前的值,如 show conf 'hive.execution.engine'
。
减少Map个数,需要增大mapred.min.split.size
的值,减少mapred.map.tasks
的值;
增大Map个数,需要减少mapred.min.split.size
的值,同时增大mapred.map.tasks
的值。
where
条件是在map端过滤,分区筛选在输入阶段过滤;在hdfs上一个分区对应一个目录;对常用字段使用分区字段,比如日期,筛选某天的数据速度显著提升;
分桶能够对原有表或者分区所存储的数据进行重新组织,使得通过分桶的方式能够快速过滤掉大量不需要遍历的文件。分桶是对文件过滤,一般使用hash模余,每个记录存储到桶的算法:记录所存储的桶=mod(hash(分桶列的值),4)
hash表示Hash函数,获取分桶列的值对应的哈希值;mod表示取余函数。
如果查询字段为分桶字段,能快速定位条件所在记录位置,而无须全表扫表,类似索引。对于大表,可以快速缩短读取数据时间,同时也能优化表的链接。比如在两表JOIN
中,相同桶的数据进行join可以节约时间。(不是一个桶的数据join不上)
可以使用hdfs dfs -ls 表路径
查看表在HDFS的存储。
使用桶的Map连接要保证连接的两张表的分桶数之间是倍数关系。
如果两个表的某字段分桶是10个,在两个表使用该字段关联join时,启用6个reduce
Hive的索引在Hive 3.0版本中被废弃,可以使用两种方式进行替换:
ORC/Parquet中存储了文件定义的Schema, ORC/Parquet可以通过Schema直接读取表所在的列,以达到列过滤的目的。
在spark中,rdd需要对每一行按分隔符分割筛选,DataFrame有表结构可直接筛选对应数据列。
HIVE中表连接的两种方式,Repartition连接和Replication连接。
Repartition连接
发生在Shuffle和Reduce阶段。一般如果不特别做其他声明,通常提到的连接就是Repartition连接。Map的任务读取A、B两个表的数据,将按连接条件发往相同的Reduce,在Reduce中计算合并的结果。
Replication连接
发生在Map阶段,Replication连接在Map阶段完成连接操作,相比发生在Shuffle阶段的Repartition连接,可以减少从HDFS读取表的次数,可以在Map 阶段实现连接时不匹配条件的记录行的过滤,减少下游网络传输的数据量和下游计算节点处理的数据量。
Replication 连接在操作时会将一个表的数据复制到各个Map 任务所在的节点并存储在缓存中,如果连接的两个表都是数据量庞大的表,会带来较大的性能问题,仅适用于两表连接中有一张小表的情况。
Replication连接根据实现的不同表连接可以分为:
普通mapjoin
-- hive命令可能被禁用,这里开启
set hive.ignore.mapjoin.hint=false;
select /*+mapjoin(t2)*/ t2.product_type
,sum(t1.salses) as sum_sale
from sales_table t1
join dim_product_info t2
on t1.product_id = t2.product_id
group by t2.product_type
在Hive中使用common map join有几种方式,方式一是使用MapJoin的hint语法。需要注意的是要关闭忽略hint的配置项,否则该方法不会生效,即set hive.ignore.mapjoin.hint=false
;
可使用Hive配置MapJoin。使用Hive配置需要使用到以下配置:
Map Join相关的Hive配置如下:
倾斜连接:
set hive.optimize.skewjoin=true;
-- 负载均衡参数
set hive.skewjoin.key=100000;
select t2.product_type
,t1.salses
from sales_table t1
join dim_product_info t2
on t1.product_id = t2.product_id
创建倾斜表:通过在创建表时指定数据倾斜键,将指定的数据键分割成单独的数据文件或者目录,这样可以加快数据过滤从而提供作业的运行速度。
--创建倾斜表student_list_bucket表
CREATE TABLE student_info_bucket (s_no STRING, s_score bigint)
--指定倾斜的键
SKEWED BY (s_score) ON (96,97)
--以目录形式存储倾斜的数据
STORED AS DIRECTORIES;
倾斜键的数据存储在Hive_DEFAULT_LIST_BUCKETING_DIR_NAME目录中(比如上面的96和97),而其他数据则存储在与该目录同一级的文件目录下。
Hive中与SkewedJoin相关的配置如下:
语句1:
select count(distinct age) as dis_cnt from user_info
count(distinct)会将同一个key的数据交给一个reduce处理,数据数据记录行多,跑批相对耗时长。以上语句由一个MR处理完成。
语句2:
select count(1) as dis_cnt
from (select age from user_info group by age) t
语句2执行计划由两个MR构成;
age年龄枚举值较少,map段预聚合,shuffle到reduce端数据量整体还是比较少,两者区别不是很明显。count(distinct)计算使用一个MR计算耗时可能会更短些。
如果key数据量比较大的情况下,两个MR处理相对会快些,比如大企业用户规模较大,查看近1年的用户活跃数(月表,用户id去重),如果使用count(distinct),如果每个月活跃去重在1亿,一年意味着大概有12亿的数据交由1个reduce去重计数。这时候交由两个MR处理,多处一个MR的开销相比时效提升几乎可以忽略不计。
在Hive 3.0中即使遇到数据倾斜,语句1将hive.optimize.countdistinct
设置为true,写法也能达到语句2的效果。
表过滤是指过滤掉同一个SQL 语句需要多次访问相同表的数据,将重复的访问操作过滤掉并压缩成只读取一次。表过滤的常见操作就是使用multi-group-by语法替换多个查询语句求并集的句式。
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
explain
insert into table insert_table partition(tp)
select s_age, min(s_birth) as birth, 'max' as label
from user_info
group by s_age
union all
select s_age, max(s_birth) as birth, 'min' as label
from user_info
group by s_age
上面的sql,user_info表会读两次
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
explain
from user_info
insert into table student_stat partition(tp)
select s_age, min(s_birth) as birth, 'max' as label
group by s_age
insert into table student_stat partition(tp)
select s_age, max(s_birth) as birth, 'min' as label
group by s_age;
hive的with语句默认生成with语句一个视图,并不会把数据物化。使用with语句代码看起来相对简洁;如果sql中with的代码块有多次调用,会重复生成with执行计划,不一定会提高执行效率。
在高版本中,with语句可物化,参数为:hive.optimize.cte.materialize.threshold
,参数默认是-1关闭。如果开启(大于0),比如n,当with…as语句被引用n次以上,会物化with生成的表,对应的with语句只执行一次。
-- 该sql中,tmp_tb1有调用了两次,该部分语句只会执行一次
set hive.optimize.cte.materialize.threshol=2
with tmp_tb1 as (
select user_id,register_date from tb
),tmp_tb2 as (
select user_id from tb2 where dt = '20220918' group by userid
)
select user_id,register_date from tmp_tb1
union all
-- tmp_tb2剔除tmp_tb1的数据
select t2.user_id,'20220918' as register_date
from tmp_tb2 t2 left join tmp_tb1 t1
on t2.user_id=t1.user_id
where t1.user_id is null
hive开启向量计算,将一次处理一条数据变为一次处理1万条数据,以此提高程序的性能
hive.vectorized.execution.enabled
:表示是否开启向量模式,默认值为false
。
开启:set hive.vectorized.execution.enabled = true;
目前MapReduce计算引擎只支持Map端的向量化执行模式,Tez和Spark计算引擎可以支持Map和Reduce端的向量化执行模式
hive.ignore.mapjoin.Hint
:是否忽略SQL中MapJoin的Hint关键,在Hive 0.11版本之后默认值为true,即开启忽略Hint的关键字。如果要使用MapJoin的Hint关键字,要在使用前开启支持Hint语法,否则达不到预期的效果。
Hint关键字,比如/*+ MAPJOIN(smalltable)*/
大表join小表
hive.auto.convert.join
:是否开启MapJoin自动优化,hive 0.11版本以前默认关闭, 0.11及以后的版本默认开启。
hive.smalltable.filesize
or hive.mapjoin.smalltable.filesize
:默认值2500000(25MB)如果大小表在进行表连接时的小表数据量小于这个默认值,则自动开启MapJoin优化。在Hive 0.8.1以前使用hive.smalltable.filesize
,之后的版本使用hive.mapjoin.smalltable.filesize
参数。
mapjoin失效情况
mapjoin在left或者right连接,小表为主表时会失效。
如下:小表 left join,大表开启了两个map,对于小表为2这一行,在上面这个map,由于没有2,大表为null,但在第二个map时,大表存在2这行有记录。这样就会出现一个问题,在大表某一个map不存在2这条记录时,大表的这个字段是为null还是2?
不可操作,所以该种情况mapjoin失效
Map端聚合通常指代实现Combiner类。Combiner也是处理数据聚合,不同于Reduce是聚合集群的全局数据。Combiner聚合是Map阶段处理后的数据,处理类似于spark里边的reduceByKey。
Map预聚合目标可以减少Shuffle数据量。如果数据经过聚合后不能明显减少,那就是浪费机器的I/O资源。
减少Shuffle数据量,开启压缩同时意味着有解压缩消耗,一般适用于大型作业。
开启文件作业的压缩只要将hive.exec.compress.intermediate
参数设置为true
压缩如果要是MapReduce中起作用,前提是需要配置mapred.output.compression. codec和mapred.output.compression两个属性。
hive.optimize.countdistinct
:默认值为true, Hive 3.0新增的配置项。当开启该配置项时,去重并计数的作业会分成两个作业来处理这类SQL,以达到减缓SQL的数据倾斜作用。
hive.exec.parallel
:默认值是False,是否开启作业的并行。默认情况下,如果一个SQL被拆分成两个阶段,如stage1、stage2,假设这两个stage没有直接的依赖关系,还是会采用窜行的方式依次执行两个阶段。如果开启该配置,则会同时执行两个阶段。在资源较为充足的情况下开启该配置可以有效节省作业的运行时间。
hive.optimize.correlation
:默认值为false,打开该配置可以减少重复的Shuffle操作。
比如sql,join已经按product_type分区,groupby没必要重新Shuffle。
select t2.product_type,sum(t1.sale) as sale
from dw_cus_sale_ptd t1
join dim_product_info t2
on t1.product_type = t2.product_type
group by t2.product_type`
文件数量大,使用分布式计算,多台机器并行计算可以显著减少计算时间。当hive数据量非常小,查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。这种情况,hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显减少。
相关参数:
set hive.exec.mode.local=true
开启本地mr
set hive.exec.mode.local.auto.inputbytes.max=5000000
设置local mr的最大数据数据量,当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M。
set hive.exec.mode.local.auto.input.files.max=
12`设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4。
Fetch抓取:hive中某些情况可以不必使用mr计算,例如:select * from table1
。这种情况,hive可以简单读取文件输出到控制台。
在hive-default.xml.tempate文件中,hive.fetch.task.conversion默认是more,老版本是minimal,这个属性修改为more后,全局查找,字段查找,limit查找不走mr计算。
在关系型数据库中使用select * from table limit 10
会全表扫描再limit。
hive.map.groupby.sorted:在Hive 2.0以前的默认值是False,2.0及2.0以后的版本默认值为true。对于分桶或者排序表,如果分组聚合的键(列)和分桶或者排序的列一致,将会使用BucketizedHiveInputFormat。
hive.vectorized.execution.mapjoin.minmax.enabled:默认值为False,是否使用vector map join哈希表,用于整型连接的最大值和最小值过滤。
CBO(成本优化器:Cost Based Optimizer)可以基于收集到的统计信息,估算出每个表连接的组合,生成一个成本代价最低的表连接方案,预先两两结合生成中间结果集,再针对这些中间结果集进行操作。
简化表的连接,在多表连接的情况下,CBO在解析SQL子句时,会识别并抽取相同的连接谓词,并根据情况适当构造一个隐式的连接谓词作为替换,以避免高昂的表连接操作。
select tb1.id
,tb2.field2
,tb3.field3
,tb4.field4
from table1 tb1
join table2 tb2
on tb1.id = tb2.id
join table3 tb3
on tb2.id = tb3.id
join table4 tb4
on tb3.id = tb4.id
正常来说,tb3的join要等待tb1和tb2的join之后发生,这样无法充分利用集群计算。优化后的执行过程可能是:tb1 join tb2和tb3 join tb4同时进行。
step1:
tb1 join tb2 -> tb_tmp1
tb3 join tb4 -> tb_tmp2
step2:
tb_tmp1 join tb_tmp2
将本地/集群上的某个文件直接插入表/分区
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename
[PARTITION (partcol1=val1, partcol2=val2 ...)]
将表或分区的数据连同元数据导出到指定的输出位置。
EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])]
TO 'export_target_path' [ FOR replication('eventid') ]
推荐:《Hive性能调优实战》