- Hive是由Facebook开源,基于Hadoop的数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。是一个Hadoop客户端,用于将HQL(Hive SQL)转化成MapReduce程序。可以选择MapReduce/Tez/Spark进行计算。
- 元数据:Metastore 元数据包括:数据库(默认是default)、表名、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。默认存储在自带的derby数据库中,由于derby数据库只支持单客户端访问,推荐使用MySQL存储Metastore。metastore服务的作用是为Hive CLI或者Hiveserver2提供元数据访问接口。
- Hive的hiveserver2服务作用是提供jdbc/odbc接口,为用户提供远程访问Hive数据的功能,用户期望在个人电脑中访问远程服务中的Hive数据,需要用到Hiveserver2。
- Hive中默认创建的表都是的内部表,也被称为管理表。对于内部表,Hive会完全管理表的元数据和数据文件。内部表意味着Hive会完全接管该表,包括元数据和HDFS中的数据。而外部表则意味着Hive只接管元数据,而不完全接管HDFS中的数据。
- Hive的log默认存放在/tmp/atguigu/hive.log目录下(当前用户名下)
- Hive启动的时候,默认申请的JVM堆内存大小为256M
- 常见炸裂函数:explode、posexplode、inline、lateral view
- 窗口函数:能为每行数据划分一个窗口,然后对窗口范围内的数据进行计算,最后将计算结果返回给该行数据
- 常用窗口函数:
- 按照功能,常用窗口可划分为如下几类:聚合函数、跨行取值函数、排名函数。
1)聚合函数max:最大值min:最小值sum:求和avg:平均值count:计数
2)跨行取值函数
(1)lag向前和lead向后
(2)first_value和last_value
3)排名函数:rank(113) dense_rank(112) row_number(123) - 用户自定义函数(UDF:user-defined function)。
- 根据用户自定义函数类别分为以下三种:
(1)UDF(User-Defined-Function)一进一出。
(2)UDAF(User-Defined Aggregation Function)用户自定义聚合函数,多进一出。
类似于:count/max/min - UDTF(User-Defined Table-Generating Functions)
- 用户自定义表生成函数,一进多出。 如lateral view explode()
- 分区表:Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区,这样的查询效率会提高很多
- 动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。
- 分桶表:对于一张表或者分区,Hive可进一步组织成桶,也就是更为细粒度的数据范围划分,分区针对的是数据的存储路径,分桶针对的是数据文件。
- Hive文件格式:Hive表数据的存储格式,可选择text file、orc、parquet、sequence file。
19. 调优
19.1 计算资源配置
计算环境为Hive on MR。计算资源的调整主要包括Yarn和MR。
19.1.1 Yarn资源配置
1)Yarn配置说明
需要调整的Yarn参数均与CPU、内存等资源有关
一个NodeManager节点分配给Container使用的内存、CPU核数
单个Container能够使用的最小内存。
19.1.2 MapReduce资源配置
MapReduce资源配置主要包括Map Task内存和CPU核数,及Reduce Task内存和CPU核数。
单个Map Task申请的container容器内存大小、CPU核数,
单个Reduce Task申请的container容器内存大小、cpu核数
19.3 Explain查看执行计划
Explain呈现的执行计划,由一系列Stage组成,这一系列Stage具有依赖关系,每个Stage对应一个MapReduce Job,或一个文件系统操作等。若某个Stage对应的一个MapReduce Job,其Map端和Reduce端的计算逻辑分别由Map Operator Tree和Reduce Operator Tree进行描述,Operator Tree由一系列的Operator组成,一个Operator代表在Map或Reduce阶段的一个单一的逻辑操作,例如TableScan Operator,Select Operator,Join Operator等。
常见的Operator及其作用如下:
TableScan:表扫描操作,通常map端第一个操作肯定是表扫描操作 Select Operator:选取操作 Group By Operator:分组聚合操作 Reduce Output Operator:输出到 reduce 操作 Filter Operator:过滤操作 Join Operator:join 操作 File Output Operator:文件输出操作 Fetch Operator 客户端获取数据操作
19.9.7 严格模式 Hive可以通过设置某些参数防止危险操作:
1)分区表不使用分区过滤
将hive.strict.checks.no.partition.filter设置为true时,对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。原因是通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
2)使用order by没有limit过滤
将hive.strict.checks.orderby.no.limit设置为true时,对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reduce中进行处理,强制要求用户增加这个limit语句可以防止Reduce额外执行很长一段时间(开启了limit可以在数据进入到Reduce之前就减少一部分数据)。
3)笛卡尔积
将hive.strict.checks.cartesian.product设置为true时,会限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。
19.4 HQL语法优化之分组聚合优化
Hive中未经优化的分组聚合,是通过一个MapReduce Job实现的。Map端负责读取数据,并按照分组字段分区,通过Shuffle,将数据发往Reduce端,各组数据在Reduce端完成最终的聚合运算。
Hive对分组聚合的优化主要围绕着减少Shuffle数据量进行,具体做法是map-side聚合。所谓map-side聚合,就是在map端维护一个hash table,利用其完成部分的聚合,然后将部分聚合的结果,按照分组字段分区,发送至reduce端,完成最终的聚合。map-side聚合能有效减少shuffle的数据量,提高分组聚合运算的效率。
19.5 HQL语法优化之Join优化
1)Common Join
Common Join是Hive中最稳定的join算法,其通过一个MapReduce Job完成一个join操作。Map端负责读取join操作所需表的数据,并按照关联字段进行分区,通过Shuffle,将其发送到Reduce端,相同key的数据在Reduce端完成最终的Join操作。如下图所示:
sql语句中的join操作和执行计划中的Common Join任务并非一对一的关系,一个sql语句中的相邻的且关联字段相同的多个join操作可以合并为一个Common Join任务。
2)Map Join
Map Join算法可以通过两个只有map阶段的Job完成一个join操作。其适用场景为大表join小表。若某join操作满足要求,则第一个Job会读取小表数据,将其制作为hash table,并上传至Hadoop分布式缓存(本质上是上传至HDFS)。第二个Job会先从分布式缓存中读取小表数据,并缓存在Map Task的内存中,然后扫描大表数据,这样在map端即可完成关联操作。
3)Bucket Map Join
Bucket Map Join是对Map Join算法的改进,其打破了Map Join只适用于大表join小表的限制,可用于大表join大表的场景。
核心思想:若能保证参与join的表均为分桶表,且关联字段为分桶字段,且其中一张表的分桶数量是另外一张表分桶数量的整数倍,就能保证参与join的两张表的分桶之间具有明确的关联关系,所以就可以在两表的分桶间进行Map Join操作了。第二个Job的Map端就无需再缓存小表的全表数据了,而只需缓存其所需的分桶即可。
4)Sort Merge Bucket Map Join(SMB Map Join)
基于Bucket Map Join。SMB Map Join要求,参与join的表均为分桶表,且需保证分桶内的数据是有序的,且分桶字段、排序字段和关联字段为相同字段,且其中一张表的分桶数量是另外一张表分桶数量的整数倍。
SMB Map Join同Bucket Join一样,同样是利用两表各分桶之间的关联关系,在分桶之间进行join操作,不同的是分桶之间的join操作的实现原理。Bucket Map Join,两个分桶之间的join实现原理为Hash Join算法;而SMB Map Join,两个分桶之间的join实现原理为Sort Merge Join算法。Hash Join和Sort Merge Join均为关系型数据库中常见的Join实现算法。Hash Join的原理相对简单,就是对参与join的一张表构建hash table,然后扫描另外一张表,然后进行逐行匹配。Sort Merge Join需要在两张按照关联字段排好序的表中进行。可以看出,SMB Map Join与Bucket Map Join相比,在进行Join操作时,Map端是无需对整个Bucket构建hash table,也无需在Map端缓存整个Bucket数据的,每个Mapper只需按顺序逐个key读取两个分桶的数据进行join即可。
19.6 HQL语法优化之数据倾斜
19.6.1 数据倾斜概述
数据倾斜问题,通常是指参与计算的数据分布不均,即某个key或者某些key的数据量远超其他key,导致在shuffle阶段,大量相同key的数据被发往同一个Reduce,进而导致该Reduce所需的时间远超其他Reduce,成为整个任务的瓶颈。
Hive中的数据倾斜常出现在分组聚合和join操作的场景中。
19.6.2 分组聚合导致的数据倾斜
19.6.2.1 优化说明
如果group by分组字段的值分布不均,就可能导致大量相同的key进入同一Reduce,从而导致数据倾斜问题。
1)Map-Side聚合
开启Map-Side聚合后,数据会现在Map端完成部分聚合工作。最佳状态下,Map-端聚合能完全屏蔽数据倾斜问题。
2)Skew-GroupBy优化
原理是启动两个MR任务,第一个MR按照随机数分区,将数据分散发送到Reduce,完成部分聚合,第二个MR按照分组字段分区,完成最终聚合。第一个mr打散数据,第二个mr按照打散后的数据进行分组聚合。
19.6.3 Join导致的数据倾斜
19.6.3.1 优化说明
未经优化的join操作,默认是使用common join算法,也就是通过一个MapReduce Job完成计算。如果关联字段的值分布不均,就可能导致大量相同的key进入同一Reduce,从而导致数据倾斜问题。有如下三种解决方案:
1)map join
使用map join算法,join操作仅在map端就能完成,没有shuffle操作,没有reduce阶段,自然不会产生reduce端的数据倾斜。该方案适用于大表join小表时发生数据倾斜的场景。
2)skew join
原理是为倾斜的大key单独启动一个map join任务进行计算,其余key进行正常的common join。
这种方案对参与join的源表大小没有要求,但是对两表中倾斜的key的数据量有要求,要求一张表中的倾斜key的数据量比较小(方便走mapjoin)。
19.7 HQL语法优化之任务并行度
对于一个分布式的计算任务而言,设置一个合适的并行度十分重要。Hive的计算任务由MapReduce完成,故并行度的调整需要分为Map端和Reduce端。
19.7.1.1 Map端并行度
M9ap端的并行度,也就是Map的个数。是由输入文件的切片数决定的。一般情况下,Map端的并行度无需手动调整。以下特殊情况可考虑调整map端并行度:
1)查询的表中存在大量小文件
若查询表中存在大量小文件,则会启动大量map task,造成资源的浪费。可以使用Hive提供的CombineHiveInputFormat,多个小文件合为一个切片,从而控制map task个数。
2)map端有复杂的查询逻辑
若SQL语句中有正则替换、json解析等复杂耗时的查询逻辑时,map端的计算会相对慢一些。若想加快计算速度,在计算资源充足的情况下,可考虑增大map端的并行度,令map task多一些,每个map task计算的数据少一些。
19.7.1.2 Reduce端并行度
Reduce端的并行度也就是Reduce个数。相对来说,更需要关注。Reduce端的并行度,可由用户自己指定,也可由Hive自行根据该MR Job输入的文件大小进行估算。
Reduce端并行度的确定逻辑如下:
若指定参数mapreduce.job.reduces的值为一个非负整数,则Reduce并行度为指定值。否则,Hive自行估算Reduce并行度,估算逻辑如下:
假设Job输入的文件大小为totalInputBytes
参数hive.exec.reducers.bytes.per.reducer的值为bytesPerReducer。
参数hive.exec.reducers.max的值为maxReducers。
则Reduce端的并行度为:
Hive自行估算Reduce并行度时,是以整个MR Job输入的文件大小作为依据的。因此在某些情况下其估计的并行度可能并不准确,此时需用户根据实际情况指定Reduce并行度了。
19.8 HQL语法优化之小文件合并
Map端输入文件合并
合并Map端输入的小文件,是指将多个小文件划分到一个切片中,进而由一个Map Task去处理。目的是防止为单个小文件启动一个Map Task,浪费计算资源。
Reduce输出文件合并
合并Reduce端输出的小文件,是指将多个小文件合并成大文件。目的是减少HDFS小文件数量。其原理是根据计算任务输出文件的平均大小进行判断,若符合条件,则单独启动一个额外的任务进行合并。
19.9 其他优化
19.9.1 CBO优化
CBO是指Cost based Optimizer,即基于计算成本的优化。Hive会计算同一SQL语句的不同执行计划的计算成本,并选出成本最低的执行计划。目前CBO在hive的MR引擎下主要用于join的优化,例如多表join的join顺序。会有更大的概率使得中间结果的数据量变小,从而使整个计算任务的数据量减小,也就是使计算成本变小。
19.9.2 谓词下推
谓词下推(predicate pushdown)是指尽量将过滤操作前移,以减少后续计算步骤的数据量。CBO优化也会完成一部分的谓词下推优化工作,因为在执行计划中,谓词越靠前,整个计划的计算成本就会越低。
19.9.3 矢量化查询
Hive的矢量化查询优化,依赖于CPU的矢量化计算,CPU的矢量化计算基本原理如下图:
Hive的矢量化查询,可以极大的提高一些典型查询场景下的CPU使用效率。
19.9.4 Fetch抓取
Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:select * from emp;在这种情况下,Hive可以简单地读取emp对应的存储目录下的文件,然后输出查询结果到控制台。
19.9.5 本地模式
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过有时Hive的输入数据量是非常小的。为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
19.9.6 并行执行
Hive会将一个SQL语句转化成一个或者多个Stage,每个Stage对应一个MR Job。默认情况下,Hive同时只会执行一个Stage。但是某SQL语句可能会包含多个Stage,但这多个Stage可能并非完全互相依赖,即有些Stage是可以并行执行的。