hive笔记

Hive笔记

1. Hive是什么?

一个SQL的解析引擎,将SQL转译成MR,本质还是MR,但是并不是所有任务都是MR

比如:select某一些字段,通过limit取出前几行,只需要把文件从上往下读top几行就可以了,不需要单独启动一个MR

什么情况下会转MR?
一般来说任务比较复杂,需要做一些shuffle。

比如 join

2. hive的本质

Hive中的表来描述数据的结构(元数据),只有表的定义,数据实际存储在HDFS上

3. hive在工作中?

Hive内容是 读多写少 。所以不支持对数据的改写和删除。

update等

4. HiveSQL和传统SQL?

HiveSQL和传统SQL是有区别的

 

可扩展性:
    UDF:    用户自定义普通函数,1对1,常用于select语句 ,对查询结构做格式化处理
    UDAF:   用户自定义聚合函数,多对1, 需要group by联合使用
    UDTF:   用户自定义表生成函数,1对多, 分词

 

延迟高:MapReduce计算框架
数据规模大:数据存在于HDFS

 

数据检查:
    HQL:读时模式:
        只有读数据的时候,hive才会检查(数据字段解析、schema),检查数据是否规范

        -优点:加载(load)数据非常迅速,因为不需要对数据做解析,仅仅是对文件的复制和移动


    SQL:写时模式:
        写的时候做数据处理(为后续查询性能,建立索引、压缩)

        -优点:读取的时候速度快,因为读之前已经对数据处理过了,读的时候没有必要花费额外的时间去对数据做进一步的检查  
        -缺点:加载数据会花费很多时间
针对大数据来说,读时模式比较多

5. Hive的系统架构

1)  用户接口cli(终端、UI、JDBC)

2)  Driver语句转换,将CMD编译成MR,Driver是整个Hive的核心

3)  数据存储:实际数据HDFS+元数据,元数据存放:
    1>  默认derby:单用户模式
    2>  mysql:多用户模式(本地+远程)

*******>>>> 尽可能将元数据和真实数据分别存放与不同的位置  <<<<**********

6. 数据管理(4种数据类型)

创建过程数据加载过程,这两个过程是分别独立完成的,也可以在同一个语句中完成

1)  Table:内部表
        数据加载过程中,实际的数据会被移动到数据仓库目录中,之后对数据的访问直接在数据仓库的目录中进行。
        删除内部表:表中数据和元数据同时被删除(硬链接)

2)  External Table:外部表
        删除外部表:元数据被删除,但是实际数据仍然存在(软连接)
        更安全,数据不完全依赖 Hive 自身管理
        数据加载过程中,实际的数据不会被移动到数据仓库目录中

#desc formatted ${tableName};

查看表结构的详细信息

表的信息::: => Table Type:表的类型

 

3)  Partition:辅助查询,缩小查询范围,加快数据检索速度
               不是所有的数据字段都适合做partition

 

4)  Bucket:
    1>  控制reduce输出文件数量,类似reduce操作(设置reduce的个数   mapred.reduce.tasks=${num}  )
    2>  采样{ TABLESAMPLE(BUCKET x OUT OF y)}
        tablesample是采样语句。语法如上。 y 必须是table总bucket数的倍数或者因子。
        1. hive 根据 y 的大小,决定采样的比例。
        2. x 表示从哪个bucket开始抽取。

     hive中table可以拆分成partition,table和partition可以通过‘CLUSTERED BY ’进一步分bucket,bucket中的数据可以通过‘SORT BY’排序。 

 

例如, table总共分了32份bucket,当 tablesample(bucket 3 out of 16),表示总共抽取了(32/16=)2 个bucket的数据,分别为第3个bucket和第(3+16=)19 个bucket的数据。

Hive的表本质就是Hadoop的目录/文件

  • hive默认表存放路径一般都是在工作目录的hive目录里面,按表名做文件夹分开,如果有分区表的话。分区值是子文件夹,可以直接在其他 M/R job 里直接应用这部分数据

问题1:内部表和外部表怎么区分?

desc formatted ${TableName};

Table Type字段:判断是内部表或者外部表

问题2:partition怎么处理?

不是所有的数据字段都适合做partition , partition的条件会成为目录的一部分,如果一个字段取值特别多
如果按照这个字段去做partition,会产生大量的数据碎片
所以适合做partition的字段,要求它们的数据内容是可以穷举出来的

比如:时间,类型

 

7. 优化

mapred.map.tasks=${num}(实际运行的并发度并不是按照这个数字来分配,只是作为一个参考)

1)  map优化——调整block大小——>并发度调整

        set mapred.max.split.size=${num};//每个map处理最大文件大小,单位是Byte,确认启动多少map数量
        set mapred.min.split.per.node=${num};//节点中可以处理最小的文件大小
        set mapred.min.split.per.rack=${num};//机架中可以处理最小的文件大小

        set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
            在开启了org.apache.hadoop.hive.ql.io.CombineHiveInputFormat后,一个data
            node节点上多个小文件会进行合并,合并文件数由mapred.max.split.size限制的大小决定。

        mapreduce——combiners优化(预处理,在map的阶段先对reduce做一个提前的聚合)
            set hive.map.aggr=${true/false} //combiners的功能开启

2)  reduce优化
        //hive.exec.reducers.bytes.per.reducer;//reduce任务处理的数据量
        mapred.reduce.tasks=${num}//设置reduce书里的数据量
        //mapred.reduce.tasks=${num}优先级高

        reduce优化后影响文件个数,因为每个reduce代表一个输出文件

3) mapreduce那些情况下会产生1个reduce的现象:
        时间上,会对数据的产生,有很大的影响。需要把所有的数据全部聚集到一个reduce节点上。
        //怎么样避免只有一个reduce的情况?
        1. 没有group by —— 有聚合函数的情况下,如果没有group by的话,会只产生一个reduce
        2. order by —— 会产生一个reduce(全局排序)
                优化方法:用distribute by和sort by来替代
                (1) sort by:不是全局排序。保证每个reduce内部是排序的,但不保证全局是有序的
                (2) distribute by:控制map端如何拆分数据给reduce,可以把它想象成partition(分桶)
                例子:  select * from ${TableName} distribute by ${字段} sort by ${列} desc;
                     //desc降序
                (3) cluster by:相当于把sort by和distribute by结合起来了,默认只能升序
                特殊形式:
                例子:  select * from ${TableName} distribute by $a sort by $a;
                改写为:select * from ${TableName} cluster by $a;
                如果用cluster by,dustribute by和sort by的字段必须一致。
        3. 笛卡尔积:join的时候不加on条件或者无效的on条件,Hive只能使用一个reduce来完成笛卡尔积

4) 加快查询速度
        1. 分区裁剪:partition
        2. 笛卡尔积:join要带on
        3. MAP-JOIN:指定小表,内存处理,通常不超过1G或者50W记录
            MAPJOIN会把小表全部读入内存中,在map阶段直接拿起另一个表的数据和内存中表数据做匹配
            由于在map阶段进行了join操作,省去了reduce运行,效率也会高很多。
        4. union all: union all(不去重)和 union(去重) => union 比 union all 花费的性能大
        5. mulit insert & multi group by
            /*  multi group by 可以将查询中的多个group
                by操作组装到一个MapReduce任务中,起到优化作用   */
        6. automatic merge:对多个小文件进行合并
                hive.merge.mapfiles = true? 是否合并Map输出文件,默认为true
                hive.merge.mapredfiles = false? 是否合并Reduce文件,默认为false
                hive.merge.size.per.task = 256*1000*1000? 合并文件的大小
                //使用的时候前面加 set
        7. Multi-Count Distinct 负载均衡(减缓数据倾斜)
                set hive.groupby.skewindata = true;

指定大表:
/*+STREAMTABLE( ${大表} )*/ 指定小表:
/*+MAPJOIB( ${小表} ) */ 不指定任何大表和小表的话,hive认为最后一个表为大表

 

使用multi group by 之前必须配置参数:

 

hive.multigroupby.singlemr
true 

5) join操作

#
(1) 语句优化:
    1. 多表连接:如果join中,多个表的join key为同一个,则join会转换为单个 MapReduce 任务
    2. 表的连接顺序:
(2) 条件判断角度:避免join过程中出现大量结果,尽量在on中完成所有条件判断

左连接时,左表中出现的join字段都保留,右表没有连接上的都为空。

执行书序是,首先完成2表join,然后再通过where条件进行过滤,这样在join过程中可能会输出大量结果,再对这些结果进行过滤,比较耗时。可以进行优化,将where条件放在on后,在join的过程中,就对不满足条件的记录进行与预先过滤。

#
(3)  并行执行:set hive.exec.parallel=true
            ——同步执行hive的多个阶段,hive在执行过程,讲一个查询转化成一个或者多个阶段。某个特定的
            job可能包含众多的阶段,而这些阶段可能并非完全相互依赖的,也就是说可以并行执行的,这样可
            能使得整个job的执行时间的缩短。

 

主要目标:解决数据倾斜问题:

总结:

1. 大表和小表之间的关联
2. 大表和大表之间的关联

Hive的优化——数据倾斜

操作:Join,Group by,Count Distinct
原因:key分布不均,人为的建表疏忽,业务数据特点
症状:1. 任务进度长时间维持在99%(或者100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。
          2. 查看未完成的子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定为发生数据倾斜。
倾斜度:1. 平均记录数超过50W且最大记录数是超过平均记录数的4倍。
              2. 最长时长比平均时长超过4分钟,且最大时长超过平均时长的2倍。
万能方法
:hive.groupby.skewindata=true

 

数据倾斜——大小表关联

原因:Hive在进行join时,按照join的key进行分发,而在join左边的表的数据会首先读入内存,如果左边表的key相对分散,读入内存的数据会比较小,join任务执行会比较快;而如果左边的表key比较集中,而这张表的数据量很大,那么数据倾斜就会比较严重。而如果这张表时效表,则还是应该把这张表放在join左边。
思路:1. 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率
          2. 使用map join让小表先进内存。
方法:Smalltable join Bigtable

 

数据倾斜——大大表关联

原因:日志中有一部分的user_id是空或者0的情况下,导致再用userid进行hash分桶的时候,会将日志中userid为0或者空的数据分到一起,导致了过大的倾斜。
思路:把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果
方法: on case when(x.uid='-' or x.uid='0'or x.uid is null) then concat('dp_hive_search',rand()) else x.uid end=f.user_id;

 

[特殊]:数据倾斜——大大表关联 (业务削减)

案例:Select * from dwlog t join dwuser t1 on t.userid=t1.userid
现象:两个表都上千万,跑起来很悬
*思路:当天登录的用户比较少
方法: ``` Select/
+MAPJOIN(t12)/ * from dwlog t11 join ( select/+MAPJOIN(t)/ t1. from ( select userid from dwlog group by userid ) t join dw_user t1 on t.userid=t1.userid ) t12 on t11.userid=t12.userid

 

数据倾斜——聚合时存在大量特殊值

原因:做count distinct时,该字段存在大量值为null或空的记录。
思路:1. count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。
          2. 如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
方法: ``` select cast(count(distinct(user_id))+1 as bigint) as usercnt
from tab
a
where userid is not null and userid <> ''

 

数据倾斜——空间换时间

案例:Select day,count(distinct sessionid),count(distinct userid) from log a group by day
问题:同一个reduce上进行distinct操作时压力很大。
方法: ``` select day, count(case when type='session' then 1 else null end) as sessioncnt, count(case when type='user' then 1 else null end) as usercnt from ( select day,sessionid,type from ( select day,sessionid,'session' as type from log union all select day userid,'user' as type from log ) group by day,sessionid,type ) t1 group by day



posted @ 2019-07-11 11:10  带了1个小才艺  阅读(147)  评论(0)    收藏  举报