HIVE 总结:
内部表(管理表)
内部表也称之为 MANAGED_TABLE;默认存储在/user/hive/warehouse下,也可以通过location指定;
**重点**:删除表时也会删除元数据和数据本身
外部表(托管表)
外部表也称之为 EXTERNAL_TABLE;在创建表时可以自己指定目录位置(location);
**重点**:删除表时只会删除元数据不会删除数据本身
分区表:
分区表实际上就是对应一个hdfs文件系统上的独立的文件夹,该文件夹下是该分区的所有数据文件。
hive中的分区就是分目录,把大的数据集根据业务分割成更小的数据集。
**作用**:在查询时通过where子句中的表达式来选择查询所需要的指定分区,这样的查询效率会提高很高。
分区表的修复:
面试题:
方法一[msck repair table emp]:加入创建了一个hive分区表,然后用hdfs的方式去-mkdir分区字段的目录,然后向这个目录下-put数据文件,然后去select,会显示表的内容为空,但是数据在的,这个时候查看元数据的partitions里面是没有这个分区字段的,此时可以用 **msck repair table emp** 命令来进行修复后就可以查到内容
方法二[alter table emp add partition(day = 15)]
hive中的高级查询:
1. order by ---> 对全局数据的排序,仅仅只有一个reduce ***数据量比较大的时候慎用!!!
2. sort by --->对每一个reduce内部数据进行排序,对于全局结果集来说不是排序 使用前先设置reduce的个数:set mapreduce.job.reduces = 3
3. distribute by ---> 作用就是分区(partition) ,类似于MapReduce中分区partition,对数据进行分区,结合sort by进行使用 如:select * from emp distribute by depno sort by empno asc;
注意:distribute by 要放在 sort by 前面[先分区再排序]
4.cluster by ---> 当distribute by 和 sort by字段相同时可以使用cluster by
UDF【user defined function】:
hive自带了很多UDF,如:max、min、split,但是往往在开发中不能满足我们的也无需求
UDF 一进一出;
UDAF(aggregation) 多进一出;
UDTF(table-generating) 一进多出
UDF开发步骤:
1.继承hive.ql.UDF类
2.实现一个或多个evaluate方法 即:重载
3.把程序打成jar包
4. [jar包在本地]:
4.11 add jar /xxx/xxx.jar
4.12 create temporary function funcname as "类的全路径"
[jar包在hdfs]
4.2 create function funcname as "类的全路径" using jar 'hdfs://xxx/xx.jar'
UDF开发注意事项:
1.UDF必须要有返回值,不能为void,且可以返回null
2.UDF中常用Text/LongWritable等类型,不推荐使用java类型,因为hive底层是用MapReduce,而mr的实现里面都是他自己独有的可序列化类型
Hive的优化:
优化1.数据压缩 [使用snappy格式] **snappy是谷歌开源的
作用:数据量小,减少网络IO流
hive底层还是走的MapReduce,也就是压缩mr阶段的数据;
具体--> 1.1 CompressedInput上传之前进行压缩; 然后客户端进行InputSplit分片,这个阶段不需要配置,因为如果是压缩后的snappy文件,map会自动进行解压
1.2map接收数据后进行DecompressInput[解压缩]对数据进行处理
1.3 map阶段SpillToDisk的时候进行压缩
配置:mapreduce.map.output.compress=true;
mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.Defaul tCodec
1.4 reduce 来map的disk取数据后进行解压缩
1.5 reduce 进行数据汇总 然后 进行压缩 输出[CompressReduceOutput]
配置:mapreduce.output.fileoutputformat.compress=true;
mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.Defaul tCodec
优化2.数据的存储格式【storage format】:列式存储的Parquet是Apache的顶级项目
我们一般select name,age from table group by xx..都是查询的列,如果读取文件时按照列来读取,那么效率会高很多
SequenceFile、TextFile:按行存储数据
ParquetFile、ORCFile :按列存储数据 【ORC里面是 strip index,索引查找】
**重要**测试显示存储在hdfs上的相同文件 create table name(...) stored as orc;和 create...stored as textfile;文件大小比例:orc : text = 1:7 大大的减少了存储的数据大小
小结:1.orc和parquet的存储格式使得存储相同的数据占得空间变小,尤其是orc
2.而列式存储相对于text、sequence的行式存储查询也是很占优势的
以上两点:压缩+数据存储格式 两者结合效果更好
create table page_views_orc_snappy(...) row format ... stored as orc tblproperties ('orc.compress'='SNAPPY');
insert into table page_views_orc_snappy select * from page_views;
//注释:这个插入语句会执行三个job: 查询page_views + 转化为orc格式 + snappy compress[压缩]
总结:
在实际的项目开发中,hive表的数据
*存储格式
orcfile / parquet
*数据压缩
snappy
优化3.Fetch-Task 值改为 more
存在的问题分析:select * from t 不会走mr,select name from t 就会走mr,为什么?
因为:
在hive-default.xml里面有个<property>是hive.fetch.task.conversion = minimal
[默认的--只有三种情况下不会走MapReduce:1.select * from t 2.select * from t where partitionname = xx 3.select * from t limit n]
我们可以在hive-site.xml里配置这个属性的值为 more
优化4.hive高级优化
1.大表拆成子表
create table table1... AS select * from table2
比如订单表,都是几百列,当我们不同需求的时候只用一些字段的时候,就到大表创建的字表里取查询,这样就比较快
2.外部表 + 分区表 [因为有可能多个部门同时在用这些数据] + [一般二级分区表较多--月/日]
create internal table name ... partitioned by (month string,day string) row format delimited...
3.数据存储格式 + 压缩 [orcfile/parquetfile + snappy]
set parquet.compress = snappy;
create table order_parquet_snappy(...)
row format ...
stored as parquet
as select * from order;
4.SQL语句的优化
优化5.数据倾斜问题:
Join:
1.Shuffle/Reduce/Commen Join
连接发生的阶段是 Reduce Task
一般是大表对大表
每个表的数据都是从文件中读取的
2.Map Join
连接发生在 Map Task
一般是小表对大表
大表的数据从文件中读取,小表的数据从内存中读取
用到了 DistributedCache,把小表缓存到了个个节点的内存中
3.SMB Join [Sort + Merge + Bucket]
一般在大公司里会用到,其实就是对reduce join的优化,因为两个大表都特别大,那么会吃不消的
set hive.enforce.bucketing = true;
set mapreduce.job.reduces = 4 [举例]
create table tablename(...) clustered by (cid) into 4 buckets row format ...
load data inpath 'xxx' into ...实质上是 hdfs dfs -put xxx 不会走MapReduce的
所以插入分桶表bucket需要用 insert into table table_bucket select * from xxx cluster by (cid),这样才会走mr
4.group by 和 count(distinct)容易造成数据倾斜 //todo:待解决
hdfs dfs -du -h /root/xxx 是看目录或者文件有多大