赞
踩
hive是基于 Hadoop平台操作 HDFS 文件的插件工具
可以将结构化的数据文件映射为一张数据库表
可以将 HQL 语句转换为 MapReduce 程序
1.hive 是由驱动器组成,驱动器主要由4个组件组成(解析器、编译器、优化器、执行器)
2.hive本身不存储数据,数据是存储在hdfs上
3.hive的元数据默认是存储在detby数据库中,但是它支持一个客户端进行连接,为了支持多客户端连接,可将元数据存储在关系型数据库中(如mysql)
4.hive本身不参与数据计算,数据计算交由计算引擎,hive支持的计算引擎由3种(MapReduce默认、Tez、Spark )
库
Hive的数据都是存储在 hdfs 上的,默认有一个根目录。由文件 hive-site.xml 中的参数是hive.metastore.warehouse.dir指定。默认为 /user/hive/warehouse
比如名为itcast的数据库存储路径为:/user/hive/warehouse/itcast.db
表
表所对应的数据是存储 在HDFS上的,而表相关的元数据是存储在关系型数据库中
hive有两种类型的表:内部表(默认表)和外部表
1.内部表:在创建表的时候没有设置external关键字,则创建的是一张内部表
表结构中:table_type:managed_table
特点:在删除表的时候,不光删除表结构,会同步将hdfs上对应的文件夹一起删除。
使用场景:由于内部表在删除表的时候会将数据文件同步删除,所以在实际的工作中,一些核心表是不会采用内部表,
如果要临时保存一些数据,或者是一些临时的计算结果则可以使用内部表
2.外部表:在创建表的时候指定了external关键字,则创建的属于一张外部表
表结构中:table_type:external_table
特点:在删除表的时候,只删除表结构,不会删除hdfs上对应的文件夹
使用场景:在实际的工作中,绝大部分的表都会采用的是外部表。
- 修改外部表emp为内部表(emp为表名)
- alter table emp set tblproperties ('EXTERNAL'='FALSE');
- 修改内部表emp为外部表
- alter table emp set tblproperties ('EXTERNAL'='TRUE');
内部表和外部表之间允许相互转换
语法:alter table 表名 set tblproperties('EXTERNAL'='FALSE|TRUE')
EXTERNAL=FALSE:代表设置为内部表
EXTERNAL=TRUE:代表设置为外部表
如果要删除外部表的数据文件方式:
1.先将表结构转换成内部表,然后删除内部表
2.先删除表结构,然后使用hdfs的命令来删除:hdfs dfs -rm -r 文件地址
分区
分区是hive的一种优化手段。分区是指根据表的字段(例如“日期day”)将表划分为不同分区
一个分区表示一个文件夹
分区:将一个大的文件夹进行拆分
分桶:将一个大的文件进行分桶
静态分区
指的是分区字段值在加载数据时,是由用户手动指定的
(1)关键语句:
partitioned by (field string)
(2)分区字段不能是表中已经存在
的字段
(3)分区字段是虚拟字段,其数据并不存储在底层的文件中
(4)分区不同,对应数据存放的文件夹不同
静态分区:手工分区,分区的名称和分区额数据都是用户来直接添加,并且一次只能向一个分区中添加数据。
添加数据的方式:
1.load data [local] inpath '文件地址' into table 表名 partition(分区列名=值)
--静态分区数据加载
load data local inpath '/root/EMP.txt' into table emp_partition partition (deptno=20);
2.insert into|overwrite table 表名 partition(分区列名=值) select 列名,列名,....from 表;
如果是静态分区加载数据,使用insert into则查询出来的数据中不能包含分区列的值。
~单分区查询
select * from emp_partition where dept=20;
~多分区查询
- select * from emp_partition where dept=20
-
- union
-
- select * from emp_partition where dept=30
alter table emp_partitionadd partition(dept=40);
dfs -mkdir -p /user/hive/warehouse/emp_partition/dept=50;
1.上传数据到分区
dfs -put /opt/modules/input/emp.txt /user/hive/warehouse/emp_partition/dept=50;
2.查询数据
select * from emp_partition where dept=50;
3.修复关系:
msck repair table emp_partition;
-- 这将删除该分区的数据和元数据
alter table emp_partition drop partition(dept=50);
alter table dept_partition drop partition ( month = '2021-02-11' ), partition(month = '2021-02-12');
alter table dept_partition drop partition ( month <= '2021-02-12' );
-- dept_partition 旧表名 ---> dept_partition2 是新表名
alter table emp_partition rename to emp_partition2;
alter table table_name partition (dt='2008-08-09') set fileformat file_format;
alter table table_name partition (dt='2008-08-09') set location "new location";
动态分区
指的是分区的字段值是基于查询结果自动推断出来的。要借助核心语法(
insert+select)
开启动态分区功能(默认 true,开启)
hive (default)> set hive.exec.dynamic.partition=true;
设置为非严格模式
hive (default)>set hive.exec.dynamic.partition.mode=nonstrict;
1.创建分区表
- create table dept_par
- (
- deptno string, -- 部门编号
- dname string -- 部门名
- )
- partitioned by (change_dt string) -- 部门改头换面日期
- row format delimited fields terminated by '\t';
2、从 表dept 中查询数据,动态插入到 表dept_par 的不同分区中
- insert into table dept_par partition (change_dt)
- select deptno ,
- dname ,
- change_dt
- from dept;
① 从表dept 中查询出 列deptno,列dname 中的数据,然后插入到 表dept_par 中
② 再从 表dept 中 查询出 列change_dt,让这一列作为 表dept_par 的分区字段
分区针对的是数据的存储路径
(分区是根据表的某一列得到的,分区不同,HDFS上的文件夹不同);分桶针对的是数据文件
(分桶是根据表的某一列下数据值,经hash取余得到的)
分区字段不能是
表中已经存在的字段;分桶的字段必须是
表中已经存在的字段
2者都是hive的一种优化手段,为了提高查询效率
- create [external] table 表名(
- 列名,......
- )partitioned by (....)
- clustered by (分桶列) into n buckets
- ......
注意:1.分桶的列是从表中的列中选出来一个作为分桶列,不需要单独定义。
2.n代表数字,表示要分的桶的数量
3.在加载数据的时候如果没有设置reduce的数量则默认reduce的数量就和桶的数量是一致的。
4.如果处理数据的时候没有设置reduce的数量,默认1个reduce,但是如果reduce处理的数据量超过1G,则系统会启动新的reduce
如果设置了reduce的数量,则处理数据的reduce就是设置的数量
分桶建议:1.选择分桶列的时候尽量选择关联的列进行分桶,这样可以提高表的关联效率。
2.选择桶的数量的时候尽量使用质数,这样可以减少数据倾斜的发生。
3.尽量在大文件中进行分桶。
4.分桶列尽量选择一些重复率比较低的列,可以减少数据与倾斜。
分桶规则:先将分桶的列的值计算hash值,然后使用改hash值对桶的数量进行取余,余数就是对应的数据所在的桶的位置,0代表第一桶。
基于分桶字段查询时,减少全表扫描
JOIN时可以提高MR程序效率,减少笛卡尔积数量
抽样:从所有的样本中抽取一部分的数据作为样本来进行进行数据分析和调试。。
注意:1.抽样可以在任何表中进行,不限制于分桶表。
2.分桶抽样其实就是在查询数据的时候对数据按照指定的列,进行逻辑分桶,不受原来表中是否分桶限制,可以重新设置分桶的列以及分桶的数量
抽样的语法:
select * from 表 tablesample(bucket n out of m [on 分桶列]);
n:代表获取的第几桶数据
m:代表桶的数量
on用来设置分桶抽样的时候分桶列,如果在一个分桶表上进行抽样,则可以将on省略,默认使用分桶表的分桶列,
如果在一个没有分桶的表上进行分桶抽样,则on是不能省略。
OLTP(on-line transaction processing):联机事务处理
OLAP(On-Line Analytical Processing):联机分析处理
OLTP | OLAP | |
---|---|---|
主要应用 | 数据库 | 数据仓库 |
业务目的 | 侧重于业务处理,如订单、支付等业务 | 侧重于数据分析 |
主要功能 | CRUD | 查询 |
响应速度 | 实时响应 | 对时间要求不严格 |
数据库设计 | 遵循3NF | 遵循星型模式/雪花模型 |
mysql | hive | |
---|---|---|
业务目的 | 侧重于业务处理,如订单、支付等 | 侧重于数据分析 |
主要功能 | CRUD | 查询 |
响应速度 | 实时响应 | 对时间要求不严格 |
数据库设计 | 遵循3NF | 遵循星型模式/雪花模型 |
处理数据规模 | 小 | 大 |
hive 和 hbase 在大数据架构中处在不同位置,hive 主要解决数据处理和计算问题,hbase 主要解决实时数据查询问题,一般是配合使用
(1)mr是基于磁盘的进行计算的,计算过程会有shuffle
(2)sql语句的解析、编译、优化、及数据的计算都由hive自身来完成
(1)spark是基于内存进行计算的
(2)sql的解析、编译、优化交由hive来处理,数据的计算却使用的是spark的rdd
sql语句的解析、编译、优化、及数据的计算都由spark自身来完成,但数据计算却不是rdd了,而是使用的是spark帮我们优化好的api( DataFrame 和 DataSet),这个api底层调用的也是rdd,但是给我spark给们进行了系统优化,开发人员直接使用api就行了
1.hive 修改 log 存储位置
重命名hive-3.1.2/conf目录下的hive-log4j.properties.template文件名称为 hive-log4j.properties
mv hive-log4j.properties.template hive-log4j.properties
2.修改log存放位置
vim hive-log4j.properties
#向其中hive.log.dir后添加你的hive所在的路径
property.hive.log.dir = /root/bigdata/hive-3.1.2/logs
hive 数据仓库的原始位置是在hdfs上的:/user/hive/warehouse路径下
编辑conf目录下的hive-site.xml
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
<description>location of default database for the warehouse</description>
</property>
hive 显示数据仓库位置配置
在hive-site.xml文件中添加如下配置信息,就可以实现显示当前数据库,以及查询表的头信息配置
<property>
<name>hive.cli.print.header</name>
<value>true</value>
</property>
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
</property>
1.hive内置的元数据库:Derby数据库
内嵌模式是hive metastore的默认部署模式。此种模式下,元数据存储在内置的Derby数据库,并且Derby数据库和metastore服务都嵌入在主hiveserver2进程中,即当启动hiveserver2进程时,Derby和metastore服务都会启动。缺点是一次只能支持一个客户端连接
本地模式
hive metastore服务随主hiveserver2而启动,并且运行在同一进程当中,但是存储元数据的数据库在单独的进程中运行,并且可以在单独的主机上,metastore服务将通过JDBC与元数据库进行通信
存储元数据的数据库推荐使用MySQL
hive根据hive.metastore.uris 参数值来判断,如果为空,则为本地模式
缺点是每启动一次hiveserver2,都会启动一个metastore服务
1.远程模式下,Metastore服务在其自己的单独JVM上运行,而不随hiveserver2启动而启动,需要单独手动启动metastore服务。如果其他进程希望与Metastore服务进行通信,就需要使用Thrift Network API进行通信
2.在生产环境中,建议用远程模式来配置Hive Metastore。在这种情况下,其他依赖hive的软件都可以通过Metastore访问hive。由于还可以完全屏蔽数据库层,因此这也带来了更好的可管理性/安全性
3.远程模式下,需要配置hive.metastore.uris 参数来指定metastore服务运行的机器ip和端口
hive \001格式数据 这种格式是hive默认的格式,不用指定任何的分割符
2.情况二:数据的字段中包含了分隔符
RegexSerDe正则加载(推荐)
面对情况一和情况二的问题,Hive中提供了一种特殊的方式来解决,Hive提供了一种特殊的Serde
来加载特殊数据的问题,使用正则匹配来加载数据,匹配每一列的数据
>>>Hive中默认提供了多种SerDe用于解析和加载不同类型的数据文件,常用的有ORCSerde 、RegexSerde、JsonSerDe等
分析数据,写正则表达式
原始数据格式
01||周杰伦||中国||台湾||男||七里香
写正则表达式
([0-9]*)\\|\\|(.*)\\|\\|(.*)\\|\\|(.*)\\|\\|(.*)\\|\\|(.*)
搜索一个在线网站,看看是否匹配
hive json格式数据
{"device":"device_30","deviceType":"kafka","signal":98.0,"time":1616817201390}
{"device":"device_32","deviceType":"kafka","signal":65.0,"time":1616817207131}
{"device":"device_32","deviceType":"kafka","signal":95.0,"time":1616817207714}
{"device":"device_71","deviceType":"bigdata","signal":45.0,"time":1616817207907}
create table tb_json_test2 (
device string,
deviceType string,
signal double,
`time` string
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' -- 指定使用专门解析json的类JsonSerDe
STORED AS TEXTFILE;
复杂json建表(array、struct)
- {
- "common": {
- "ar": "230000",
- "ba": "iPhone",
- "ch": "Appstore",
- "is_new": "1",
- "md": "iPhone 8",
- "mid": "YXfhjAYH6As2z9Iq",
- "os": "iOS 13.2.9",
- "uid": "485",
- "vc": "v2.1.134"
- },
- "actions": [
- {
- "action_id": "favor_add",
- "item": "3",
- "item_type": "sku_id",
- "ts": 1585744376605
- }
- ],
- "displays": [
- {
- "displayType": "query",
- "item": "3",
- "item_type": "sku_id",
- "order": 1,
- "pos_id": 2
- },
- {
- "displayType": "query ",
- "item": "6",
- "item_type": "sku_id",
- "order": 5,
- "pos_id": 1
- }
- ],
- "page": {
- "during_time": 7648,
- "item": "3",
- "item_type": "sku_id",
- "last_page_id": "login",
- "page_id": "good_detail",
- "sourceType": "promotion"
- },
- "err": {
- "error_code": "1234",
- "msg": "***********"
- },
- "ts": 1585744374423
- }
- create external table ods_log_inc
- (
- `common` struct<ar :string,ba :string,ch :string,is_new :string,md :string,mid :string,os :string,uid :string,vc
- :string> comment '公共信息',
- `page` struct<during_time :string,item :string,item_type :string,last_page_id :string,page_id
- :string,source_type :string> comment '页面信息',
- `actions` array<struct<action_id:string,item:string,item_type:string,ts:bigint>> comment '动作信息',
- `displays` array<struct<display_type :string,item :string,item_type :string,`order` :string,pos_id
- :string>> comment '曝光信息',
- `err` struct<error_code:bigint,msg:string> comment '错误信息',
- `ts` bigint comment '时间戳'
- ) comment '活动信息表'
- row format serde 'org.apache.hadoop.hive.serde2.jsonserde';
1.开启事务配置
- set hive.support.concurrency = true; --Hive是否支持并发
- set hive.enforce.bucketing = true; -- 是否开启分桶功能 从Hive2.0开始不再需要
- set hive.exec.dynamic.partition.mode = nonstrict; --动态分区模式 非严格
- set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; -- 事务管理类
- set hive.compactor.initiator.on = true; --是否在Metastore实例上运行启动线程和清理线程
- set hive.compactor.worker.threads = 1; --在此metastore实例上运行多少个压缩程序工作线程
2.创建Hive事务表
- create table trans_student(
- id int,
- name String,
- age int
- )clustered by (id) into 2 buckets stored as orc TBLPROPERTIES('transactional'='true');
保存表中的所有的数据的历史变化状态,记录数据从开始到当前的所有状态变化的信息
生效时间:该数据添加或者是修改的时间
失效时间:该条数据过期的时间,一般如果没有失效使用9999-12-31表示,如果失效了泽一般设置的时间就是抽取时间-1天
使用场景:表中数据量过大,部分字段发生变化 ,变化频率不高
闭链:拉链表中某一个数据发生变化,修改这条数据的失效时间为抽取的前天
开链:修改表中的数据或是新增的数据,作为数据的最新状态;
Oracle中:
1.先增量抽取数据。
2.将抽取到的数据和拉链表中现有的数据进行匹配(merge into),找到能够匹配到的并且是最新的那一条数据,进行闭链操作(修改失效时间)。
3.将抽取过来的数据直接追加到拉链表中,进行开链操作(insert into)。
--编写存储过程来实现拉链表
CREATE OR REPLACE PROCEDURE pro_increment_his(work_date VARCHAR2)
IS
BEGIN
--闭链操作
MERGE INTO user_t_his t USING (SELECT * FROM user_t WHERE to_char(last_date,'yyyy-mm-dd')=work_date)s
ON(t.id=s.id)
WHEN MATCHED THEN
--修改失效时间
UPDATE SET end_date=to_date(work_date,'yyyy-mm-dd')-1 WHERE t.end_date=to_date('9999-12-31','yyyy-mm-dd');
--开链
INSERT INTO user_t_his
SELECT t.*,
to_date(work_date,'yyyy-mm-dd'),
to_date('9999-12-31','yyyy-mm-dd')
FROM user_t t WHERE to_char(last_date,'yyyy-mm-dd')=work_date;
END;
1.查询所有的最新的数据
select * from 拉链表 where 失效时间=‘9999-12-31’;
2.查询某一个时间节点的切片数据
select * from 拉链表 where 生效时间<=时间节点 and 失效时间>=时间节点
Hive中:
在hive中构建拉链表使用左连接来完成拉链表的闭链操作,然后在使用union all完成开链操作,最后将处理的结果使用
insert overwrite将原来拉链表的数据进行覆盖操作
拉链表语法结构:
insert overwrite table 临时拉链表
select a.*,'抽取日期','9999-12-31' from 原表 a where 日期=抽取日期
union all
select a.列名 .....
if(b.列名 is not null and a.失效时间='9999-12-31','抽取日期-1',a.失效日期)
from 拉链表 a left join (select * from 原表 where 日期=抽取日期) b
on a.关联字段=b.关联字段
1. load data local inpath '本地文件路径' [overwrite] into table 表名;
overwrite:是覆盖文件,没有overwrite是追加新的内容
from>on>join>where>Group by>聚合函数(例如分组后统计数量)>select>
Hiving>distinct>order>limit
count(*)==count(1)
count(1):
统计所有行,包含nullcount(字段名称):
统计所有行,但不包含该字段下为null的行
- --对两表并行查询,删除重复行,同时进行排序
- select num,name from student_local
- union
- select num,name from student_hdfs;
- --对两表并行查询,保留重复行,进行排序
- select num,name from student_local
- union all
- select num,name from student_hdfs;
Sort By 分区排序,数据排序在Reducer前完成,数据随机被分配到各个分区,如果要指定数据去哪个分区,需要使用Distribute By
Distribute By+Sort By 类似于Cluster By,不过Distribute By负责分区,Sort By 负责区内排序,分区字段和排序字段可以不同
Distribute By:类似MR中partition,进行分区,分区规则:hash散列
Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前
如果DISTRIBUTE BY +SORT BY的字段一样,并且升序排序,可以得出下列结论:
CLUSTER BY=DISTRIBUTE BY +SORT BY(字段一样)
1.内连接:和oracle中的内连接一样,但是hive中默认是不支持笛卡尔积和不等值连接,
如果要进行不等值连接,则必须要设置模式为:nonstrict
--设置非严格模式
set hive.mapred.mode=nostrict;
2.左半开连接:left semi join
由于早期的hive中不支持in和exists子查询,所以使用左半开连接来实现子查询的功能。
语法:select * from 表 a left semi join 表 b on a.列=b.列;
执行结果:只返回左表总符合关联条件的数据,并不会返回右表的数据。
- create table if not exists stu(
- uid int,
- cname string,
- score int
- );
-
- insert into stu values (1,'语文',98);
- insert into stu values (1,'数学',78);
- insert into stu values (1,'英语',88);
- insert into stu values (2,'语文',67);
- insert into stu values (2,'数学',87);
- insert into stu values (2,'英语',79);
- insert into stu values (3,'语文',69);
- insert into stu values (3,'数学',92);
- insert into stu values (3,'英语',91);
- insert into stu values (4,'语文',100);
-
- Select * from stu;
-
- -- 方式一 : 通过 GROUP BY + CASE WHEN + 聚合函数
- select uid,sum(case when cname='语文' then score else 0 end) chinese,
- sum(case when cname='数学' then score else 0 end) math,
- sum(case when cname='英语' then score else 0 end) English
- from stu group by uid;
- CREATE TABLE IF NOT EXISTS user_order (
- uid BIGINT
- ,order_id BIGINT
- );
-
- insert into user_order values (1,112);
- insert into user_order values (1,113);
- insert into user_order values (2,114);
- insert into user_order values (2,155);
- insert into user_order values (3,11);
- -- 方式二: 通过 GROUP BY + CONCAT_WS + COLLECT_LIST
- -- 不去重 列表形式
- select uid,collect_list(order_id) from user_order group by uid;
- -- 去重:
- select uid,collect_set(order_id) from user_order group by uid;
- SELECT
- uid
- ,CONCAT_WS(',', COLLECT_LIST(order_str)) AS order_list
- FROM
- (
- SELECT uid , CAST(order_id AS STRING) AS order_str
- FROM user_order
- ) tmp
- GROUP BY uid
- ;
- CREATE TABLE IF NOT EXISTS explode_laterview_org(
- day1_num BIGINT
- ,day2_num BIGINT
- ,day3_num BIGINT
- ,day4_num BIGINT
- ,day5_num BIGINT
- ,day6_num BIGINT
- ,day7_num BIGINT
- ,campaign_name STRING
- ,campaign_id BIGINT
- );
-
-
- INSERT OVERWRITE TABLE explode_laterview_org VALUES
- (40, 20, 10, 4, 4, 2, 1, 'zoo', 2 )
- ,(100, 80, 53, 40, 7, 6, 5, 'moji', 3)
- ;
- select * from explode_laterview_org;
-
- select campaign_id,campaign_name,'day1_num' type ,day1_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day2_num' type ,day2_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day3_num' type ,day3_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day4_num' type ,day4_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day5_num' type ,day5_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day6_num' type ,day6_num num from explode_laterview_org
- union all
- select campaign_id,campaign_name,'day7_num' type ,day7_num num from explode_laterview_org
- order by campaign_id;
- SELECT
- campaign_id, campaign_name, type, num
- FROM explode_laterview_org
- LATERAL VIEW
- EXPLODE(
- STR_TO_MAP(
- CONCAT(
- 'day1_num=',CAST (day1_num AS STRING),
- '&day2_num=',CAST (day2_num AS STRING),
- '&day3_num=',CAST (day3_num AS STRING),
- '&day4_num=',CAST (day4_num AS STRING),
- '&day5_num=',CAST (day5_num AS STRING),
- '&day6_num=',CAST (day6_num AS STRING),
- '&day7_num=',CAST (day7_num AS STRING)
- )
- ,'&', '=')
- ) lateral_table AS type, num
- ;
hive支持的数据存储格式有TextFile(默认) SequenceFile Parquet ORC,但是尽量使用Parquet和ORC文件存储格式
(1)行式存储:
优点:数据被保存在一起了,insert和update更加容易
缺点:如果查询只涉及某几个列,它会把整行数据都读取出来,不能跳过不必要的列读取
(2)列式存储:
优点:最大的优势是查询时可以快速跳过没有涉及到的列,从而避免全表扫描;支持编码压缩;谓词下推、映射下推
缺点:insert/update会比较麻烦并且不适合扫描小量的数据
选择parquet原因:
选择ORC原因:
(1)比Parquet 的压缩效率高(eg:snappy)
(2)ORC存储格式对hive非常友好
(3)支持事务ACID(支持事务的表必须为分桶表)
(4)支持不同的索引索引机制(意味着orc查询速度快)
ORC为我们提供了两种索引机制:Row Group Index(行组索引) 和 Bloom Filter Index(布隆过滤器)
Row Group Index(行组索引)
在stripe(行组)记录了每个字段的最大最小值,当查询中有<,>,=的操作时,会根据最大最小值,跳过扫描不包含的stripes
Bloom Filter Index(布隆过滤器)
判读数据在不在,当它说一个值不存在的时候,一定不存在,当它说一个值存在的时候,可能存在
在数据规模很大和工作负载密集的情况下,采用数据压缩对磁盘I/O操作、网络数据传输有极大的帮助
hive 中的压缩就是使用了hadoop中的压缩实现的,所以hadoop中支持的压缩在hive 中都可以直接使用
hadoop中支持的压缩算法:
压缩方式选择时重点考虑:解压缩速度、压缩率、压缩后是否可以支持切片
压缩格式 | 是否支持切片 | 解压缩速度 | 压缩率 |
---|---|---|---|
snappy | no | 最快 | 很差 |
lzo | yes | 很快 | 很高 |
bzip2 | yes | 最慢 | 最高 |
gzip | no | 一般 | 很高 |
lzo压缩算法的缺点:
需要手动为文件创建索引,没有索引不支持文件切片
所有压缩算法的缺点:
加重CPU负荷,算法越复杂,解压时间越长
- 设置map后输出压缩
- 1.开启hive中间传输数据压缩功能
- set hive.exec.compress.intermediate=true;
-
- 2.开启mapreduce中map输出压缩功能
- set mapreduce.map.output.compress=true;
-
- 3.设置mapreduce中map输出数据的压缩方式
- set mapreduce.map.outout.compress.codec=
- org.apache.hadoop.io.compress.SnappyCodec
- org.apache.hadoop.io.compress.GzipCodec
- org.apache.hadoop.io.compress.BZip2Codec
- org.apache.hadoop.io.compress.Lz4Codec
- 设置reduce后输出压缩
- 1.开启hive最终输出数据压缩功能
- set hive.exec.compress.output=true;
-
- 2.开启mapreduce最终输出数据压缩
- set mapreduce.output.fileoutputformat.compress=true;
-
- 3.设置mapreduce最终数据输出压缩方式
- set mapreduce.output.fileoutputformat.compress.codec =
- org.apache.hadoop.io.compress.SnappyCodec
- org.apache.hadoop.io.compress.GzipCodec
- org.apache.hadoop.io.compress.BZip2Codec
- org.apache.hadoop.io.compress.Lz4Codec
-
- 4.设置mapreduce最终数据输出压缩为块压缩
- set mapreduce.output.fileoutputformat.compress.type=BLOCK;
开启本地模式
原因:有时候数据量不大的表用本地计算模式处理,时间会很短,但是默认情况下会将任务提交到集群,等待资源分配,这个过程不仅繁琐,而且更浪费时间
限制条件:如果以下任意一个条件不满足,那么即使开启了本地模式,将依旧会提交给YARN集群运行
1.处理的数据量不超过128M
2.MapTask的个数不超过4个
3.ReduceTask的个数不超过1个
原理:JVM指代一个Java进程,假设一个mr程序中有100个MapTask,那么Hadoop默认会为每个MapTask启动一个JVM(共100个),JVM频繁的创建和销毁,会导致内存开销较大,为了解决上述问题,Hadoop中提供了JVM重用机制来,JVM重用机制可以使得一个JVM实例在同一个job中被使用N次(不同mr job中不可以),即当一个MapTask运行结束以后,JVM不会进行释放,而是继续供让一个MapTask使用,直到运行了N个以后,就会释放,N的值可以在Hadoop的mapred-site.xml文件中进行配置,通常在10-20之间,也可以再hive中直接进行设置
使用条件:适用于大量小文件场景,没有大量小文件,就不需要开启。因为开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放
Hive会将一个查询解析为多个Stage,即阶段(例如MapReduce阶段、抽样阶段、合并阶段、limit阶段),有时候Stage彼此之间有依赖关系,只能挨个执行,但是在一些别的场景下,很多的Stage之间是没有依赖关系的,例如Union语句,Join语句等等,这些Stage没有依赖关系,但是Hive依旧默认挨个执行每个Stage,这样会导致性能非常差,我们可以通过修改参数,开启并行执行,当多个Stage之间没有依赖关系时,允许多个Stage并行执行,提高性能
- -- 打开任务并行执行,默认为false
- set hive.exec.parallel=true;
- -- 同一个sql允许最大并行度,默认为8
- set hive.exec.parallel.thread.number=16;
一个Select 语句有Group by 也有 order by 时
Hive会使用两个MapReduce来完成这两个操作,第一个MapReduce做group by,经过shuffle阶段对id做分组,第二个MapReduce对第一个MapReduce的结果做order by,经过shuffle阶段对id进行排序,这样会导致性能相对较差,当我们在Hive中开启关联优化后,可以把分组和排序放在同一个MapReduce中实现
- -- 默认false
- set hive.optimize.correlation=true;
Hive实现Join时,为了提高性能,提供了多种Join方案,例如适合小表Join大表的Map Join,大表Join大表的Reduce Join,以及大表Join的优化方案Bucket Join等
- -- 默认已经开启了Map Join
- hive.auto.convert.join=true
- -- hive会自动对表数据量进行判读,若到达小表条件,就将小表就加入内存
Hive会自动判断是否满足Map Join,如果不满足Map Join的条件,则自动执行Reduce Join
小表数据首会分发给每个MapTask的内存一份,然后逐次取出大表部分数据和小表进行join,底层不需要经过shuffle
分桶字段 = Join字段 ,桶的个数相等或者成倍数
- -- 开启分桶普通join,默认false
- set hive.optimize.bucketmapjoin = true;
- -- 开启分桶SMB join
- set hive.optimize.bucketmapjoin = true;
- -- 默认true
- set hive.auto.convert.sortmerge.join=true;
- -- 默认false
- set hive.optimize.bucketmapjoin.sortedmerge = true;
- -- 默认true
- set hive.auto.convert.join.noconditionaltask=true;
经shuffle分组后,将key相同的数据分发到同一个reducer,实现大表之间的joinHive会自动判断是否满足Map Join,如果不满足Map Join,则自动执行Reduce Join
distinct的命令会在内存中构建一个hashtable,查找去重的时间复杂度是O(1),但这个关键字在使用后所有数据只会由一个Reduce Task进行处理,在大数据背景下,可能会导致Reduce Task内存溢出
group by 会分组,然后在分组内排序,如果排序方式为快速排序的话,时间复杂度是比较高O(nlogn),虽然排序花费时间长,但是不会内存溢出;另外(group by)去重会转化为两个任务,会消耗更多的磁盘网络I/O资源
on 中谓词 where 中谓词,on不仅可以作为连接条件,也可以作为过滤条件
(1)left join:右侧的表过滤条件写在on后面,左侧的表过滤条件写在where后面,性能上有提高
(2)join:写在哪里都一样
(3)full join:过滤条件写在 where 后可以谓词下推,写在 on 后不可以谓词下推(默认cbo引擎下)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。