目录
HIVE的基本理解,使用,特性
什么是hive
hive元数据
hive默认分隔符 \001
hive行级更新操作的前提条件
hive/mysql/hbase比较
函数
hive解决wordcount案例
hive内部表与外部表
hql特性:
hive常用命令:
读取数据文件方法:
查看yarn mr日志
HIVE动态分区
HIVE锁表问题
HIVE数据倾斜
hql性能调优
hive 小表与大表关联
执行MR或聚集查询卡死
HIVE的基本理解,使用,特性
什么是hive
hive------mapreduce的封装,意义在于将sql语言转化为mapreduce的过程,本质是个mapreduce,批处理强大,不支持单条纪录级别的update操作,随机读写性能差 (hive是个计算框架,不能存储数据)
hbase-----hdfs的包装,本质是数据存储,克服hdfs在随机读写上的缺点
kudu-----不及HDFS批处理快,也不及HBase随机读写能力强,但是反过来它比HBase批处理快(适用于OLAP的分析场景),而且比HDFS随机读写能力强,适用于实时写入或者更新的场景。
hive的表本质就是hadoop的目录/文件(文件夹),hive依托hdfs存储,依托yarn资源调度,依托mapreduce进行计算
hive元数据
hive元数据默认存储在derby中,也可存储与mysql中,元数据是指表的信息,比如表的名字,表有哪些列等等描述信息。我们向表中插入的数据是保存在HDFS上的。
hive默认分隔符 \001
hive行级更新操作的前提条件
1 注意存储格式按ORC方式
2 进行数据分桶
3 添加表属性:"transactional"="true" 该设置不可逆,使得该表
4.hive-site.xml里要做相关配置 参见 https://blog.csdn.net/wzy0623/article/details/51483674
hive/mysql/hbase比较
hive | mysql | hbase |
数据量 | 大 | 大 |
速度 | 数据量大时快 | 数据量小时快 |
查询 | 增删改 | 增删改 |
函数
系统函数: 月: date_format last_day 周: next_day 日:date_add date_sub 解析json: get_json_object
rank() over() 1,1,3,4,5,6,7 跳跃排序
row_number() over() 1,2,3,4,5,6,7
dense_rank() over() 1,1,2,3,4,5,6 连续排序(最大排名会小于总数)
hive解决wordcount案例
select word,count(*) from (
select explode(split(sentence.' ')) word from article
) t
group by word
hive内部表与外部表
create table create external table
内部表 vs 外部表
表结构和数据均丢失 表结构丢失,但数据仍在
不可挽回 把表重建,数据自动恢复
hql特性:
1.0.13版本前的hive仅支持from 后面的子查询,0.13版本后的hive新增支持 in(not in)后面的子查询/ EXISTS(NOT EXISTS)后面的子查询
2. 子查询相当于表名,必须有别名。
3. hive 不支持union ,只支持union all
4. 子查询中使用union all 时,在子查询里不能使用count、sum 等 聚合函数
5. 两表直接进行union all 可以使用count、sum 等聚合函数
6. 两张表进行union all 取相同的字段名称,可正常输出指定数据内容,且结果为两张表的结果集
hive常用命令:
普通创建:
-- 创建表,external 外部表
CREATE external TABLE IF NOT EXISTS t2(id int,name string,age int)
COMMENT 'xx' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE ;
-- 加载数据到hive表
load data local inpath '/home/centos/customers.txt' into table t2 ; -- local上传文件
load data inpath '/user/centos/customers.txt' [overwrite] into table t2 ; -- 移动文件
-- 加载数据到分区表
load data local inpath '/home/centos/customers.txt' into table t3 partition(year=2014,month=11);
-- 启用/禁用表
ALTER TABLE t2 ENABLE NO_DROP; -- 不允许删除
ALTER TABLE t2 DISABLE NO_DROP; -- 允许删除
-- 复制表
create table tt as select * from users ; -- 携带数据和表结构
create table tt like users ; -- 不带数据,只有表结构
分区表:
-- 创建分区表.
create table t3(id int,name string,age int) partition by (year int,month int) row farmat delimited fields terminated by ',' stored as textfile;
-- 显式表的分区信息
show partitions t3;
-- 添加分区,创建目录
alter table add partition (year = 2021,month = 03)
-- 删除分区
alter table t3 drop if exists partition (year = 2021,month = 03)
-- 分区结构
/user/hive/warehouse/mydb2.db/t3/year=2014/month=11
/user/hive/warehouse/mydb2.db/t3/year=2014/month=12
-- 加载数据到分区表
load data [local] inpath '/home/centos/customers.txt' [overwrite] into table t3 [partition (year 2021,month 03)]
分桶表:
-- 创建桶表t4
create table t4 (id int,name string,age int) clusted by (id) into 3 buckets row farmat delimited fields terminated by ',' stored as textfile;
-- 加载数据不会进行分桶操作
load data [local] inpath '/home/centos/customers.txt' into table t4;
-- 查询t3表数据插入到t4中。
insert into t4 select id,name,age from t3;
桶表的数量如何设置?
评估数据量,保证每个桶的数据量block的2倍大小。(从2.7.3版本开始,官方关于Data Blocks 的说明中,block size由64 MB变成了128 MB的。)
既分区又分桶:
create table t_test (id int)
partitioned by (type string)
clustered by (id) into 3 buckets
row format delimited fields terminated by '\t';
-- partition by 要写在clustered by 前面
hive删除数据:
hive删除数据不支持单条纪录级别
--------------------------------------- 分区表
----------------删除具体partition
alter table t4 drop if exists partition (year = 2021,month = 02);
----------------删除partition内部分数据
insert overwrite into table t4 partition (year = 2021,month = 02)
select * from t4 where year = 2021 and month = 02 and age<20;
--------------------------------------- 非分区表
INSERT OVERWRITE TABLE t4 SELECT * FROM t4 WHERE age is not null;
读取数据文件方法:
TextFile , SequenceFile(二进制) , RCFile
SequenceFile(二进制): 是hadoop提供的一种二进制文件,<key,value>形式序列化到文件中.java Writable接口进行序列化和反序列化
RCFile: 是hive专门推出的面向列的数据格式
查看yarn mr日志
查看application的日志:
[[email protected] ~]$ yarn logs -applicationId application_1523430872525_0002
查看具体某一个container的日志:
[[email protected] ~]$ yarn logs -applicationId application_1523430872525_0002 -containerId container_1523191604137_0016_02_000001 -nodeAddress hadoop01:60127
HIVE动态分区
hive单字段动态分区:(默认最后一个字段对应分区字段)
hive>
create table dpartition(id int ,name string )
partitioned by(ct string );
hive>
hive.exec.dynamici.partition=true; #开启动态分区,默认是false
set hive.exec.dynamic.partition.mode=nonstrict; #开启允许所有分区都是动态的,否则必须要有静态分区才能使用。
insert overwrite table dpartition
partition(ct)
select id ,name,city from mytest_tmp2_p;
要点:因为dpartition表中只有两个字段,所以当我们查询了三个字段时(多了city字段),所以系统默认以最后一个字段city为分区名,因为分区表的分区字段默认也是该表中的字段,且依次排在表中字段的最后面。
hive>--查看可知,hive已经完成了以city字段为分区字段,实现了动态分区。
hive (fdm_sor)> show partitions dpartition;
partition
ct=beijing
ct=beijing1
hive多字段半自动分区:(静态分区要放在动态分区前面,分区字段顺序和partition 字段顺序一致)
1.创建一个只有一个字段,两个分区字段的分区表
hive (fdm_sor)> create table ds_parttion(id int )
> partitioned by (state string ,ct string );
2.往该分区表半动态分区插入数据
hive>
set hive.exec.dynamici.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table ds_parttion
partition(state='china',ct) #state分区为静态,ct为动态分区,以查询的city字段为分区名
select id ,city from mytest_tmp2_p;
hive多字段全部动态分区:(注意顺序)
set hive.exec.dynamici.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table ds_parttion
partition(state,ct)
select id ,country,city from mytest_tmp2_p;
注意:字段的个数和顺序不能弄错。
动态参数必备参数:
- hive.exec.dynamic.partition 开启动态分区,默认不开
- hive.exec.dynamic.partition.mode 动态分区的模式:默认strict,要求必须要有个静态分区字段;一般需设置为nonstrict表示所有分区字段可使用动态分区
- hive.exec.max.dynamic.partitions.pernode 每个执行MR的节点上最大能创建的分区数(比如一年365天,分区数要设置>365)
- hive.exec.max.dynamic.partitions 所有MR节点上最大能创建的分区数
- hive.exec.max.created.files 整个MR JOB中最大能创建的hdfs文件数
Hive的静态分区,实际上就是手动指定分区的值为静态值,适用于小批量数据
HIVE锁表问题
hive有两种锁,一种是 共享锁(SHARED),查询时会有。SHARED(共享锁 S)和 Exclusive(排他锁 X)。只有都是共享锁才不会锁表/分区。
解决方法:
1.先查看有没有锁。表级查看和分区级查看。
// 1 查询是否锁表:
hive> show locks ;
// 2 发现表:test 被锁
// 3 临时解决办法
hive> unlock table test; //亲测这个命令基本没啥用,表依然处于无法操作状态,但是可以试试
hive> unlock table test partition(dt='2019-05-05'); //解锁分区锁命令可以用这个
SHOW LOCKS <TABLE_NAME>;
SHOW LOCKS <TABLE_NAME> EXTENDED;
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>);
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>) EXTENDED;
2.调整sql语句或者插入数据操作之间设置sleep或者设置相关关于hive锁冲突时重新等待锁释放的参数
3.关闭锁机制,set hive.support.concurrency=false
4.表建立分区,这样锁就会到分区级别,就会降低锁表粒度。动态分区如非必要就关闭动态分区,因为动态分区的话,锁级别就到表,不到分区。 set hive.exec.dynamic.partition=false
5.关闭事务:set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager
HIVE数据倾斜
阐述数据倾斜的原因:
数据分布不均匀;不同数据类型进行关联操作(只会有一个reduce);空数值易造成
解决数据倾斜的方法:
1.mapjoin 在map端做join操作减少数据,减少到reduce端汇总的数据
2.如果是不同数据类型关联造成的就在sql中转成一致的数据类型再关联
3. group by操作
4.开启数据倾斜时的负载均衡 set hive.groupby.skewindata=true
就是到reduce那后对于大的reduce再进行reduce 2个MRJOB
5.控制空值分布 将为空的key转变为字符串加纯随机数,将因空值而造成倾斜的数据分布到多个reducer (本质和开启数据倾斜时的负载均衡是一样的)
hql性能调优
1. mapjoin默认打开
set hive.auto.convert.join = true; --是否开自动mapjoin
set hive.mapjoin.smalltable.filesize; --mapjoin的表size大小
以上两个参数同时使用,在hive.auto.convert.join为true时,只要小表size小于hive.mapjoin.smalltable.filesize的设置值,并且小表不是关联操作的最后一张表,小表就会走mapjoin。
MAPJION会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多。
set hive.auto.convert.join = true;
set hive.mapjoin.smalltable.filesize = 6250000;
select * from table_1 --小表,size 5m
join table_2
on 1=1;
mapjoin还有一个很大的好处是能够进行不等连接的join操作,如果将不等条件写在where中,那么mapreduce过程中会进行笛卡尔积,运行效率特别低,如果使用mapjoin操作,在map的过程中就完成了不等值的join操作,效率会高很多。
mapjoin适用的场景: 关联操作中有一张表非常小;不等值的链接操作
2.行列过滤,就是在join操作前先进行where操作,减少数据集
3.做好分区。(分桶用于采样)
4.小文件
CombineHiveInputformat 减少切片,进而减少Maptask,减少内存
开启JVM重用(减少开关时间)
打开merge功能 ==========> 如果是maponly 任务,merge功能默认打开;如果是mapreduce任务,需要打开merge功能
merge功能就是 执行完任务后,自动将小于16M的文件,合并到256M (hive块的大小)
5.合理设置map个数和reduce个数
6.启用压缩 好处:减少磁盘空间,减少网络传输 坏处:增加了解压缩的计算
7.采用列式存储orc,parquet 提高查询效率;提高压缩比例
8.在map端开启 combiner set hive.map.aggr = true
hive 小表与大表关联
关于小表join大表的补充:
表join时的操作是这样的:一般是驱动表和另一张表,另一张表最好是小表,将另一张表加载入内存。在驱动表里每行匹配的时候,全表扫描小表。
a left outer join b a是驱动表,b应是小表
a right outer join b b是驱动表,a应是小表
执行MR或聚集查询卡死
yarn节点分配给nodemanager运行资源的内存不够,就易出现执行MR卡死的状况,
调整参数 yar.nodemanager.resource.memory-mb (集群中某个计算节点分配给nodemanager的最大可用内存,这个最大可用内存不是该节点最大内存,而是该节点最大内存划分出来的给nodemanager使用的内存)