1、Explain查看执行计划
explain可以查看执行计划
-- 创建大表
create table bigtable(id bigint,t bigint,uid string,keyword string,url_rank int,click_num int,click_url string
)
row format delimited
fields terminated by '\t';
-- 创建小表
create table smalltable(id bigint,t bigint,uid string,keyword string,url_rank int,click_num int,click_url string
)
row format delimited
fields terminated by '\t';
-- 创建JOIN后表
create table jointable(
id bigint,t bigint,uid string,keyword string,
url_rank int,click_num int,click_url string
)
row format delimited
fields terminated by '\t';
使用explain
-- 1、没有走MR的HQL
explain select * from bigtable; -- 这个HQL我们并没有走MR
hive (test)> explain select * from bigtable;
OK
STAGE DEPENDENCIES: -- 阶段的依赖关系
Stage-0 is a root stage -- 根阶段(也就是阶段0)
STAGE PLANS: -- 阶段计划
Stage: Stage-0 -- 阶段0
Fetch Operator -- Stage-0是一个抓取操作
limit: -1 -- 说明并没有做limit限制
Processor Tree: -- 操作树
TableScan -- 扫描的表
alias: bigtable -- 表bigtable
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
Select Operator -- 查询列
expressions: id (type: bigint), t (type: bigint), uid (type: string), keyword (type: string), url_rank (type: int), click_num (type: int), click_url (type: string) -- 具体的查询的列
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6 -- 输出列名,自起的
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
ListSink
Time taken: 0.4 seconds, Fetched: 17 row(s)
-- 2、走MR的HQL
explain select click_url,count(*) ct from bigtable group by click_url;
hive (test)> explain select click_url,count(*) ct from bigtable group by click_url;
OK
STAGE DEPENDENCIES: -- 依赖的阶段
Stage-1 is a root stage -- 阶段1,根阶段
Stage-0 depends on stages: Stage-1 -- 阶段0,并且阶段0依赖阶段1
STAGE PLANS: -- 阶段计划
Stage: Stage-1 -- 阶段1
Map Reduce -- map reduce阶段
Map Operator Tree: -- map阶段
TableScan -- 扫描的表
alias: bigtable -- 具体的表,bigtable
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE -- 表的状态
Select Operator -- 查询操作
expressions: click_url (type: string) -- 查询的内容
outputColumnNames: click_url -- 输出的列
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE -- 查询的状态
Group By Operator -- 分组的操作
aggregations: count() -- 分组的操作时count()
keys: click_url (type: string) -- 分组的字段
mode: hash -- 采用的模式是hash
outputColumnNames: _col0, _col1 -- 输出字段为两个
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE -- 状态
Reduce Output Operator -- reduce的输出操作
key expressions: _col0 (type: string)
sort order: + -- 排序方式为正序
Map-reduce partition columns: _col0 (type: string) -- MR的分区字段,也就是第一个字段
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
value expressions: _col1 (type: bigint)
Reduce Operator Tree: -- reduce阶段
Group By Operator -- 分组操作
aggregations: count(VALUE._col0) -- 聚合操作
keys: KEY._col0 (type: string)
mode: mergepartial
outputColumnNames: _col0, _col1
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
File Output Operator
compressed: false
Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
table:
input format: org.apache.hadoop.mapred.TextInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Stage: Stage-0 -- 第二阶段,也是个抓取阶段
Fetch Operator
limit: -1 -- 没有限制抓取的行数
Processor Tree: -- 操作树
ListSink
Time taken: 0.163 seconds, Fetched: 48 row(s)
-- 3、查看的更加详细的信息
explain extended select * from bigtable;
explain extended select click_url,count(*) ct from bigtable group by click_url;
这种加了extended关键字的用法,在我们查看MR任务的时候基本不使用的,因为多出来的字段对我查看MR任务并没有帮助
2、hive建表优化
1、分区表
hive中的分区其实就是分目录,把一个大的数据集分割成一个个小的数据集,可以指定分区进行查询,可以很大的提高效率
分区的具体操作分区表分为静态分区和动态分区
-- 以下为静态分区
-- 创建分区表
create table dept_partiton(
deptno int,
dname string,
loc string
)
partitioned by (day string) -- 分区字段不能是表中已经存在的字段,而这个分区字段也称为伪类
row format delimited fields terminated by '\t';
-- 加载数据 ,这里必须要指定分区
load data /opt/apps/data/20211112.log into table dept_partiton partition(day='20211112');
-- 查询数据
select * from dept_partition where day='20211112';
select * from dept_partition where day='20211112'
union
select * from dept_partition where day='20211113'
union
select * from dept_partition where day='20211114';
-- 添加分区
alter table dept_partiton add partition(day='20211115');
alter table dept_partiton add partition(day='20211116') partition(day='20211117');
-- 删除分区
alter table dept_partition drop partition(day='20211115');
alter table dept_partition drop partition(day='20211116'),partition(day='20211117');
-- 查看分区表有多少分区
show partitions dept_partition;
-- 查看分区表结构
desc formatted dept_partition;
-- 二级分区
create table dept_partition2(
deptno int,
dname string,
loc string
)
partitioned by (day string,hour string)
row format delimited fields terminated by '\t';
-- 二级分区加载数据
load data local inpath '/opt/apps/1.log' into table dept_partition2 partition(day='20211112',hour='12');
-- 二级分区查询数据
select * from dept_partition2 where day='20211112' and hour='12';
-- 动态分区
-- 在进行动态分区的时候需要设置一些参数
-- 1、开启动态分区功能(m默认true,开启)
set hive.exec.dynamic.partition=true;
-- 2、设置非严格模式(动态分区模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrist模式表示允许所有分区字段都可以使用动态分区)
set hive.exec.dynamic.partition.mode=nonstrict;
-- 3、在所有执行MR的节点上,最大一共可以创建多少个动态分区。默认1000
set hive.exec.max.dynamic.partitions=1000;
-- 4、在每个执行MR的节点上,最大可以创建多少个动态分区
-- 该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值 100,则会报错。
set hive.exec.max.dynamic.partiitons.pernode=100;
-- 5、整个MR Job中,最大可以创建多少个HDFS文件。默认100000
set hive.exec.max.created.files=100000
-- 6、当有空分区生成时,是否抛出异常。一般不需要设置,默认false
set hive.error.on.empty.partition=false
-- 创建动态分区表的时候需要有两个表,一个目标表,还有一个是原表
-- 需求,将dept表中的数据按照地区(loc字段),插入到目标表dept_partition的相应分区中
-- 1、创建目标分区表(也就是动态分区表)
create table dept_partition_dy(id int,name string)
partition by (loc int)
row format delimited fields terminated by '\t';
-- 2、设置动态分区
set hive.exec.dynamic.partiiton.mode = nonstrict;
insert into table dept_partition_by partition(loc) select deptno,dname,loc from dept;
-- 3、查看目标分区表的分区情况
show partitions dept_partition;
2、分桶表
分区针对的是数据的存储路径,分桶针对的是数据文件
分通是对分区进行更加细粒度的划分
-- 创建一个分桶表
create table stu_buck(id int,name string)
clustered by(id) into 4 buckets
row format delimited fields terminated by '\t';
-- 查看表结构
desc formatted stu_buck;
-- 导入数据到分桶表中,load方式
load data inpath '/stu.txt' into table stu_buck;
-- 查询分桶的数据
select * form stu_buck;
-- 分桶规则:
-- Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶中
-- 分桶操作需要注意的事项
-- 1、reduce的个数设置为-1,让Job自行决定需要用多少个reduce或者将reduce的个数设置为大于等于分桶表的桶数
-- 2、从hdfs中load数据到分桶表中,避免本地文件找不到问题
-- 3、不要使用本地模式
-- insert 方式将数据导入分桶表
insert into table stu_buck select * from student_insert;
-- 抽样查询
select * from stu_buck tablesample(bucket 1 out of 4 on id);
-- 我们在使用分桶表的时候大多是进行抽样查询
3、合适的文件格式
Hive支持的存储数据的格式主要有:textfile,sequencefile,orc,parquet
行存储:textfile,sequencefile
列存储:orc,parquet
行存储的特点:如果经常用select * 适合用行存储
列存储:单个行进行查询效率高
1、textfile
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用,但使用Gzip这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作
2、Orc格式
Orc是hive 0.11引入新的存储格式
3、Parquet格式
Parquet文件是以二进制方式存储的,所有是不可以直接读取的,文件中包含该文件的数据和元数据。因此Parquet格式文件是自解析的
4、格式的压缩方式
压缩格式 | hadoop 自带? | 算法 | 文件扩展名 | 是否可切分 | 换成压缩格式后,原来的程序是否需要修改 |
---|---|---|---|---|---|
DEFLATE | 是,直接使用 | DEFLATE | .deflate | 否 | 和文本处理一样,不需要修改 |
Gzip | 是,直接使用 | DEFLATE | .gz | 否 | 和文本处理一样,不需要修改 |
bzip2 | 是,直接使用 | bzip2 | .bz2 | 是 | 和文本处理一样,不需要修改 |
LZO | 否,需要安装 | LZO | .lzo | 是 | 需要建索引,还需要指定输入格式 |
Snappy | 否,需要安装 | Snappy | .snappy | 否 | 和文本处理一样,不需要修改 |
在工作中使用最多的是LZO和Snappy,因为他们都有着优秀的压缩能力和压缩效率