一、Hive介绍
1.1 Hive介绍
1.1.1 OLTP和OLAP
数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。
- OLTP 系统强调数据库内存效率,强调内存各种指标的命令率,强调绑定变量,强调并发操作;
- OLAP 系统则强调数据分析,强调SQL执行市场,强调磁盘I/O,强调分区等。
1.1.2 OLTP和OLAP区别
项目 | OLTP | OLAP |
---|---|---|
用户 | 操作人员,底层管理人员 | 决策人员,高级管理人员 |
功能 | 日常操作处理 | 分析决策 |
DB设计 | 面向应用 | 面向主题 |
数据 | 当前的,最新的新界的,二维的分立的 | 历史的,聚集的,多维的,集成的统一的 |
存取 | 读写数十条记录 | 读写百万条记录 |
工作单位 | 简单的事务 | 复杂查询 |
用户数 | 上千个 | 上百万个 |
DB大小 | 100MB-GB | 100GB-TB |
时间要求 | 具有实时性 | 对时间要求不严格 |
主要应用 | 数据库 | 数据仓库 |
1.1.3 Hive结构
Apache Hive™数据仓库软件支持使用SQL读取、写入和管理驻留在分布式存储中的大型数据集。结构可以投影到已 经存储的数据上。提供了一个命令行工具和JDBC驱动程序来将用户连接到Hive。 Hive不能单独使用,它依赖HDFS。Hive不存储数据,它的数据存储到HDFS。Hive本身也不具备分析能力,它依赖 了底层的分布式计算框架(Mapreduce/spark)。 hive本身最开始facebook发布的。最终要mapreduce来处理来自它本身社交平台的海量数据。hive纳入到apache 的基金会。 以下为hive结构图:
hive有3中使用方式:
- CLi命令行
- JDBC/ODBC api接口:使用之前要启动Thrift server服务
- Web GUI页面
1.1.4 Hive元数据管理
Hive元数据管理默认使用Derby,只是Hive内嵌的数据库,支持单会话。也可以指定其他数据库管理元数据,如Mysql
- Derby:内嵌自带,单会话
- MySQL:支持多会话,需求额外进行配置
1.2 Hive安装与使用
1.2.1 Hive安装
1、上传hive安装包apache-hive-1.2.1-bin.tar.gz到linux
2、上传mysql的驱动jar包mysql-connector-java-5.1.47-bin.jar到linux
3、解压hive安装包
4、修改hive-env.sh.template 名称为 hive-env.sh
5、修改hive-env.sh
HADOOP_HOME=/opt/hadoop-2.8.1
export HIVE_CONF_DIR=/opt/hive-1.2.1/conf
6、修改环境变量
export HIVE_HOME=/opt/hive-1.2.1
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$HIVE_HOME/bin
1.2.2 Hive启动
启动hive之前要先启动hdfs和yarn,如果hdfs启动了但是hive还是无法连接,请检查你的hdfs是否处于安全模式。如果是安全模式,请先退出hdfs的安全模式之后,再尝试连接hive。
CLi启动:
$hive
Beeline启动:
# 启动Thrift
$ hive --service hiveserver2 & (&:作用是在后台启动)
$ hive --service metastore &
#启动Beeline
$ beeline
$ beeline> !connect jdbc:hive2://hdp22:10000
$ Enter username for jdbc:hive2://hdp22:10000: root
$ Enter password for jdbc:hive2://hdp22:10000: 123456
或
$ beeline -u jdbc:hive2://hdp22:10000
1.2.3 MYSQL管理元数据(可选)
mysql创建hive用户
mysql>CREATE USER 'hive' IDENTIFIELD BY '123456'
mysql>GRANT ALL PRIVILEGES ON *.* TO 'hive'@'%' WITH GRANT OPTION;
mysql>flush privileges;
修改conf/hive-site.xml文件
javax.jdo.option.ConnectionURL
jdbc:mysql://localhost/hive?createDatabaseIfNotExist=true
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
javax.jdo.option.ConnectionUserName
hive
javax.jdo.option.ConnectionPassword
password
将驱动包复制到lib/目录
cp mysql-connector-java-5.1.47-bin.jar hive-1.2.1/lib/
1.2.4 测试
1、查看数据库: show databases;
2、创建数据库:
create database hive;
use hive;
3、创建表
create table t_user3 (
id int,
name string,
sex string,
money double
)
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile;
解释
row format delimited 行格式化
fieids terminated by '\t' 属性之间用什么分割
lines terminated by '\n' 行之间用什么分割
stored as textfile 存成什么数据
tip:
当表和库建好之后,会在hdfs的对应目录下生成一系列的目录:
/user/hive/warehouse/hive.db/t_user
4、查看表
show tables;
5、上传数据
load data [local] inpath '/home/user.txt' into table t_user;
tip: 导入数据到指定的表中
local : 表示从本地文件系统(linux)中导入数据,如果不加local表示从hdfs文件系统中导入数据。
6、查看表
hive> select * from t_user;
OK
1 lixi man 1000.0
2 rock woman 1001.0
7、退出hive
quit;
1.3 DDL
1.3.1 数据库
(1)增
CREATE DATABASE IF NOT EXISTS database_name
(2)删
DROP DATABASE [IF EXISTS] database_name
DROP DATABASE [IF EXISTS] database_name RESTRICT //非严格的
DROP DATABASE [IF EXISTS] database_name CASCADE //级联删除
(3)改
//修改属性
ALTER DATABASE [IF EXISTS] database_name SET DBPROPERTIES (property_name=property_value,...)
//修改所有者
ALTER DATABASE [IF EXISTS] database_name SET OWNER [USER|ROLE] user_or_role
//修改位置
ALTER DATABASE [IF EXISTS] database_name SET LOCATION hdfs_path
(4)使用
USE database_name
USE DEFAULT //使用默认数据库
(5)显示
SHOW DATABASES //显示所有数据库
1.3.2 创建表
语法
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name -- (Note: TEMPORARY available in Hive 0.14.0 and later)
[(col_name data_type [column_constraint_specification] [COMMENT col_comment], ... [constraint_specification])]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[SKEWED BY (col_name, col_name, ...) -- (Note: Available in Hive 0.10.0 and later)]
ON ((col_value, col_value, ...), (col_value, col_value, ...), ...)
[STORED AS DIRECTORIES]
[
[ROW FORMAT row_format]
[STORED AS file_format]
| STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)] -- (Note: Available in Hive 0.6.0 and later)
]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)] -- (Note: Available in Hive 0.6.0 and later)
[AS select_statement]; -- (Note: Available in Hive 0.5.0 and later; not supported for external tables)
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
LIKE existing_table_or_view_name
[LOCATION hdfs_path];
data_type
: primitive_type
| array_type
| map_type
| struct_type
| union_type -- (Note: Available in Hive 0.7.0 and later)
primitive_type
: TINYINT
| SMALLINT
| INT
| BIGINT
| BOOLEAN
| FLOAT
| DOUBLE
| DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later)
| STRING
| BINARY -- (Note: Available in Hive 0.8.0 and later)
| TIMESTAMP -- (Note: Available in Hive 0.8.0 and later)
| DECIMAL -- (Note: Available in Hive 0.11.0 and later)
| DECIMAL(precision, scale) -- (Note: Available in Hive 0.13.0 and later)
| DATE -- (Note: Available in Hive 0.12.0 and later)
| VARCHAR -- (Note: Available in Hive 0.12.0 and later)
| CHAR -- (Note: Available in Hive 0.13.0 and later)
array_type
: ARRAY < data_type >
map_type
: MAP < primitive_type, data_type >
struct_type
: STRUCT < col_name : data_type [COMMENT col_comment], ...>
union_type
: UNIONTYPE < data_type, data_type, ... > -- (Note: Available in Hive 0.7.0 and later)
row_format
: DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
[NULL DEFINED AS char] -- (Note: Available in Hive 0.13 and later)
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
file_format:
: SEQUENCEFILE
| TEXTFILE -- (Default, depending on hive.default.fileformat configuration)
| RCFILE -- (Note: Available in Hive 0.6.0 and later)
| ORC -- (Note: Available in Hive 0.11.0 and later)
| PARQUET -- (Note: Available in Hive 0.13.0 and later)
| AVRO -- (Note: Available in Hive 0.14.0 and later)
| JSONFILE -- (Note: Available in Hive 4.0.0 and later)
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
column_constraint_specification:
: [ PRIMARY KEY|UNIQUE|NOT NULL|DEFAULT [default_value]|CHECK [check_expression] ENABLE|DISABLE NOVALIDATE RELY/NORELY ]
default_value:
: [ LITERAL|CURRENT_USER()|CURRENT_DATE()|CURRENT_TIMESTAMP()|NULL ]
constraint_specification:
: [, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
[, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
[, CONSTRAINT constraint_name FOREIGN KEY (col_name, ...) REFERENCES table_name(col_name, ...) DISABLE NOVALIDATE
[, CONSTRAINT constraint_name UNIQUE (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
[, CONSTRAINT constraint_name CHECK [check_expression] ENABLE|DISABLE NOVALIDATE RELY/NORELY ]
例子:
(1)创建表
========================================================
CREATE TABLE IF NOT EXISTS IPTV_JSCN_NJ.std_category (
colum1 type,
colom2 type,
...
)
ROW FORMAT DELIMITED -- 行格式化
FIELDS TERMINATED BY '\001' -- 列分割符号 -- 默认为 '\001' (ctrl + A 或者 ^A)
LINES TERMINATED BY '\n' -- 行分割符号
STORED AS TEXTFILE; -- 存成什么数据
LOCATION "/user/hive/warehouse/hive.db/t_user" -- 表数据存储目录
(2)创建外部表
=======================================================
使用【EXTERNAL】作为标识
内部表和外部表的区别
1. 删除内部表:删除元数据,数据删除
2. 删除外部表:删除元数据,数据不删除
CREATE 【EXTERNAL】 TABLE IF NOT EXISTS IPTV_JSCN_NJ.std_category (
colum1 type,
colom2 type,
...
)
ROW FORMAT DELIMITED -- 行格式化
FIELDS TERMINATED BY '\001' -- 列分割符号 -- 默认为 '\001' (ctrl + A 或者 ^A)
LINES TERMINATED BY '\n' -- 行分割符号
STORED AS TEXTFILE; -- 存成什么数据
LOCATION "/user/hive/warehouse/hive.db/t_user" -- 表数据存储目录
(3)创建分区表
=======================================================
CREATE 【EXTERNAL】 TABLE IF NOT EXISTS IPTV_JSCN_NJ.std_category (
colum1 type,
colom2 type,
...
)
PARTITIONED BY (dt string, siteKey string) -- 使用dt和siteKey作为分区字段
ROW FORMAT DELIMITED -- 行格式化
FIELDS TERMINATED BY '\001' -- 列分割符号 -- 默认为 '\001' (ctrl + A 或者 ^A)
LINES TERMINATED BY '\n' -- 行分割符号
STORED AS TEXTFILE; -- 存成什么数据
LOCATION "/user/hive/warehouse/hive.db/t_user" -- 表数据存储目录
(4)创建分桶表
必须设置reduceTask个数(决定了分桶个数):set mapreduce.job.reduces=3;
=======================================================
CREATE 【EXTERNAL】 TABLE IF NOT EXISTS IPTV_JSCN_NJ.std_category (
colum1 type,
colom2 type,
...
)
PARTITIONED BY (dt string, siteKey string) -- 使用dt和siteKey作为分区字段
CLUSTERED BY (colum1) SORTED BY (colum1 ASC) INTO 3 BUCKETS -- 以colum1作为分桶字段,使用colum1排序,分3个桶
ROW FORMAT DELIMITED -- 行格式化
FIELDS TERMINATED BY '\001' -- 列分割符号 -- 默认为 '\001' (ctrl + A 或者 ^A)
LINES TERMINATED BY '\n' -- 行分割符号
STORED AS TEXTFILE; -- 存成什么数据
LOCATION "/user/hive/warehouse/hive.db/t_user" -- 表数据存储目录
1.2.2 删除表
(1)删除表
=========================
DROP TABLE table_name
(2)删除表(重建表,表数据丢失)
=========================
TRUNCATE TABLE table_name
1.2.3 修改表
- 严格读时模式 : 在hive进行数据导入的时候并不会校验你的数据格式是否符合hive表的规范,只有在你进行查询的才会去校验你的文件中的数据的格式,如果格式不满足就会使用NULL来替代你的字段。
- 严格写时模式 : 在进行数据插入的时候会严格的校验你的语法格式。最典型的例子,就是有主外键关联的表,你在插入一个有外键的值的时候,外键的值必须要从另一个关联表中的主键中选择其中一个值。
(1)修改表结构
=========================
Alter Table
Rename Table【修改表名称】
Alter Table Properties【修改表属性】
Change Column Name/Type/Position【修改列名称,数据类型,位置】
Add/Replace Columns【添加列,替换所有列】
1.修改表名称:ALTER TABLE table_name RENAME table_name2
2.修改表属性:ALTER TABLE table_name SET TBLPROPERTIES ('EXTERNAL' = 'TRUE'); -- 修改内部表为外部表
3.修改列名称:ALTER TABLE table_name CHANGE COLUMN name1 name2 string;
4.修改列位置:ALTER TABLE table_name CHANGE COLUMN name1 name2 string FIRST; -- 移到第一列
5.修改列位置:ALTER TABLE table_name CHANGE COLUMN name1 name2 string AFTER id -- 移到某列之后
6.添加列:ALTER TABLE table_name ADD COLUMNS (id int, name string)
7.整体替换列:ALTER TABLE table_name REPLACE COLUMNS(id int,name string)
(2)修改表分区
=========================
Alter Partition
Add Partitions【添加分区】
Dynamic Partitions【动态分区】
Rename Partition【重命名分区】
Drop Partitions【删除分区】
1.添加分区: ALTER TABLE table_name ADD PARTITION (location = 'value1')
2.重命名分区:ALTER TABLE table_name PARTITION location_old RENAME TO PARTITION location_new
3.删除分区: ALTER TABLE table_name DROP [IF EXISTS] PARTITION(location = value1)
1.2.4 查询表
1.查看表结构:DESC tablename
2.查看表详细结构:DESC EXTENDED tablename -- 含扩展信息
3.查看表格式化结构:DESC FORMATTED tablename -- 含扩展信息
4.查看DDL语句:SHOW CREATE TABLE table_name
例:
hive> desc extended t_1;
OK
id int
name string
sex string
money double
Detailed Table Information Table(tableName:t_1, dbName:hive, owner:root, createTime:1557309921, lastAccessTime:0, retention:0, sd:StorageDescriptor(cols:[FieldSchema(name:id, type:int, comment:null), FieldSchema(name:name, type:string, comment:null), FieldSchema(name:sex, type:string, comment:null), FieldSchema(name:money, type:double, comment:null)], location:hdfs://y51:9000/user/hive/warehouse/hive.db/t_1, inputFormat:org.apache.hadoop.mapred.TextInputFormat, outputFormat:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat, compressed:false, numBuckets:-1, serdeInfo:SerDeInfo(name:null, serializationLib:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, parameters:{line.delim=
, field.delim= , serialization.format= }), bucketCols:[], sortCols:[], parameters:{}, skewedInfo:SkewedInfo(skewedColNames:[], skewedColValues:[], skewedColValueLocationMaps:{}), storedAsSubDirectories:false), partitionKeys:[], parameters:{commment=this is jianghai0702 table, last_modified_time=1557378293, totalSize=76, numRows=-1, rawDataSize=-1, COLUMN_STATS_ACCURATE=false, numFiles=2, transient_lastDdlTime=1557378293, last_modified_by=root}, viewOriginalText:null, viewExpandedText:null, tableType:MANAGED_TABLE)
1.4、DML
1.4.1 加载数据
文件->Table
hive> LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
1.4.2 插入数据
将数据插入在某表,会执行mapreduce
2.1 Into 是追加数据
hive> INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]]
select_statement1 FROM from_statement;
2.2 Overwrite 是将数据进行覆盖
hive> INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement1 FROM from_statement;
1.4.3 插入目录
将数据写到某目录下
hive> INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT row_format] [STORED AS file_format]
SELECT ... FROM ...
e.g.
hive> insert overwrite directory '/write'
row format delimited
select * from part_buk;
1.4.4 插入表(values方式)
(插入数据,values传值方式)
hive> INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...]
e.g.
hive> insert into t_stu values(4,'qphone','woman',18,'java');
1.4.5 更新数据(X)
(支持hive中支持ACID的事务的文件格式;如:Orc;使用thrift服务的方式才能使用)
update操作不会修改原有的数据,而是会创建一个新的版本,在新的版本中将要修改的数据做一个标记
UPDATE tablename SET column = value [, column = value ...] [WHERE expression]
e.g.
1. 修改hive-site.xml
hive.support.concurrency
true
hive.enforce.bucketing
true
hive.exec.dynamic.partition.mode
nonstrict
hive.txn.manager
org.apache.hadoop.hive.ql.lockmgr.DbTxnManager
hive.compactor.initiator.on
true
hive.compactor.worker.threads
1
2. 建表
create table t_stu3 (
id int,
name string,
sex string,
age int,
subject string
)
clustered by (id) into 2 buckets
row format delimited
fields terminated by ','
stored as orc
TBLPROPERTIES('transactional'='true');
insert into t_stu3
select * from t_stu;
update t_stu3 set name='curry',subject='basketball' where id=17;
1.4.6 删除数据(X)
DELETE FROM tablename [WHERE expression]
1.4.7 合并小文件
小文件预防(hive2默认开启)
//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000
有些公司用的版本不同,低版本可能有些配置不一样,最好检查一下上面这些配置是否设置,然后根据自己的实际集群情况进行设置。
小文件的产生原因
- 动态分区插入的时候,保证有静态分区,不要误判导致产生大量分区,大量分区加起来,自然就有大量小文件;
- 如果源表是有大量小文件的,在导入数据到目标表的时候,如果只是
insert into dis select * from origin
的话,目标表通常也有很多小文件。如果有分区,比如dt, hour
,可以使用distribute by dt, hour
,保证每个小时的数据在一个reduce里面; - 类似
sqoop
增量导入,还有hive
一些表的查询增量导入,这些肯定是有小文件的,需要进行一周甚至一天定时任务的小文件合并。
小文件解决
从小文件产生的途经就可以从源头上控制小文件数量,方法如下:
1.使用Sequencefile作为表存储格式,不要用textfile,在一定程度上可以减少小文件。
2.减少reduce的数量(可以使用参数进行控制)。
3.少用动态分区,用时记得按distribute by分区。
对已有的
1.使用hadoop archive命令把小文件进行归档。
2.重建表,建表时减少reduce数量。
3.通过参数进行调节,设置map/reduce端的相关参数,如下:
上面是平时开发数据任务时候,小文件的预防,但如果由于我们的大意,小文件问题已经产生了,就需要解决了。通常就是insert overwrite
了。
insert overwrite table test [partition(hour=...)] select * from test distribute by floor (rand()*5);
注:这个语句把test
表的数据查询出来,overwrite
覆盖test
表,不用担心如果overwrite
失败,数据没了,这里面是有事物性保证的,可以观察一下执行的时候,在test表hdfs
文件目录下面有个临时文件夹。如果是分区表,加上partition
,表示对该分区进行overwrite
。如果是orc格式存储的表,还可以使用alter table test [partition(...)] concatenate
进行小文件的合并,不过这种方法仅仅适用于orc格式存储的表。
1.4.8 导入导出:IMPORT 、EXPORT
- 只支持HDFS
语法:
导出语法
EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])]
TO 'export_target_path' [ FOR replication('eventid') ]
导入语法
IMPORT [[EXTERNAL] TABLE new_or_original_tablename [PARTITION (part_column="value"[, ...])]]
FROM 'source_path'
[LOCATION 'import_target_path']
导入
将log.txt导入table_1
IMPORT TABLE table_1 FROM '/home/log.txt'
将log.txt导入table_1的name1分区
IMPORT TABLE table_1 PARTITION(partition="name1")
FROM '/home/log.txt'
导出
将table_1数据导出到00
EXPORT TABLE tabel_1 TO '/home/00'
将table_1的name1分区的数据导出到00
EXPORT TABLE tabel_1 PARTITION(partition="name1")
TO '/home/00'
1.4.9 导入导出:使用插入数据的方式实现
- 支持HDFS和本地Local
导入
1 本地系统中导入 load data local inpath '' into table
2 hdfs中导入 load data inpath '' into table
3 直接将文件上传到hdfs的表目录中
4 克隆数据:location
5 表与表之间直接进行导入
insert into destine
select * from source;
6 create as
create table destine
as
select * from source;
7 批量导入
FROM t_index
insert into table t_insert
SELECT * where id = 4
insert into table hive.t_stu
SELECT * where id = 1
;
导出
1. 导出到本地文件系统
2. 导出到hdfs系统
3. 建一个表的数据导入到另一个表中
关键字:insert overwrite
---导出到本地文件系统
insert overwrite local directory '/home/00'
select * from t_index;
---导出到本地文件系统并且指定分隔符
insert overwrite local directory '/home/01'
row format delimited fields terminated by ','
select * from t_index;
---导出hdfs
insert overwrite directory '/01'
row format delimited fields terminated by ','
select * from t_index;
1.4.10 EXPLAIN解析Hive
https://cwiki.apache.org/conf...
- 通过explain或者explain extended来查看执行计划。(通过sql语句翻译成mapreduce程序)
- 通过EXPLAIN来优化SQL语句
explain
select * from t_buk;
explain extended
select * from t_buk;
explain select * from t_buk;
STAGE DEPENDENCIES:
Stage-0 is a root stage
STAGE PLANS:
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
TableScan
alias: t_buk
Statistics: Num rows: 12 Data size: 207 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type: int), name (type: string), sex (type: string), money (type: double)
outputColumnNames: _col0, _col1, _col2, _col3
Statistics: Num rows: 12 Data size: 207 Basic stats: COMPLETE Column stats: NONE
ListSink
explain extended select * from t_buk;
ABSTRACT SYNTAX TREE:
TOK_QUERY
TOK_FROM
TOK_TABREF
TOK_TABNAME
t_buk
TOK_INSERT
TOK_DESTINATION
TOK_DIR
TOK_TMP_FILE
TOK_SELECT
TOK_SELEXPR
TOK_ALLCOLREF
STAGE DEPENDENCIES:
Stage-0 is a root stage
STAGE PLANS:
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
TableScan
alias: t_buk
Statistics: Num rows: 12 Data size: 207 Basic stats: COMPLETE Column stats: NONE
GatherStats: false
Select Operator
expressions: id (type: int), name (type: string), sex (type: string), money (type: double)
outputColumnNames: _col0, _col1, _col2, _col3
Statistics: Num rows: 12 Data size: 207 Basic stats: COMPLETE Column stats: NONE
ListSink
1.5、DQL
Where语句
SELECT * FROM sales WHERE amount > 10 AND region = "US"
DISTINCT 去重
hive> SELECT col1, col2 FROM t1
1 3
1 3
1 4
2 5
hive> SELECT DISTINCT col1, col2 FROM t1
1 3
1 4
2 5
hive> SELECT DISTINCT col1 FROM t1
1
2
PARTITION 分区
- See also Partition Filter Syntax.
- See also Group By.
- See also Sort By / Cluster By / Distribute By / Order By.
SELECT page_views.*
FROM page_views
WHERE page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31'
LIMIT 分页
SELECT * FROM customers LIMIT 5
SELECT * FROM customers ORDER BY create_date LIMIT 2,5
分组:GROUP BY
https://cwiki.apache.org/conf...
为了按性别计算不同用户的数量:(将查到的数据插入到表中)
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count (DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;
高级功能:多组分组插入
FROM pv_users
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count(DISTINCT pv_users.userid)
GROUP BY pv_users.gender
INSERT OVERWRITE DIRECTORY '/user/facebook/tmp/pv_age_sum'
SELECT pv_users.age, count(DISTINCT pv_users.userid)
GROUP BY pv_users.age;
分桶:CLUSTER/DISRIBUTE BY
https://cwiki.apache.org/conf...
- Cluster by (不能使用局部排序)
- Distribute by ... sort by ... (sort局部排序,order by:全局排序)
语法(可用于数据导入):
SELECT col1, col2 FROM t_stu CLUSTER BY col1;
SELECT col1, col2 FROM t_stu DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC;
必须设置reduceTask个数(决定了分桶个数):
set mapreduce.job.reduces=3;
排序:SORT/ORDER BY
- sort by:局部排序
- order by:全局排序
SELECT col1, col2 FROM t_stu ORDER BY col1 ASC, col2 DESC;
SELECT col1, col2 FROM t_stu DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC;
连接:INNER/LEFT/RIGHT/FULL JOIN
https://cwiki.apache.org/conf...
1.允许复杂的连接表达式
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a LEFT OUTER JOIN b ON (a.id <> b.id)
2.可以在同一查询中加入两个以上的表
SELECT a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key2)
3.【key相同视为一个作业】如果对于每个表在连接子句中使用相同的列,Hive会将多个表上的连接转换为单个map / reduce作业,
SELECT a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key1)
4.【key不同视为不同作业】转换为两个map / reduce作业,因为b中的key1列用于第一个连接条件,而b中的key2列用于第二个连接条件。第一个map / reduce作业与a连接,然后在第二个map / reduce作业中将结果与c连接。
SELECT a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key2)
5.【大表在最后】在连接的每个map / reduce阶段中,序列中的最后一个表通过reducers流式传输,其他表在缓冲区中。因此,通过组织表使得最大的表出现在序列的最后,有助于减少reducer中用于缓冲连接键的特定值的行所需的内存。例如in
SELECT a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key1)
6.【指定流式传输表】在连接的每个map / reduce阶段,可以通过提示指定要流式传输的表。例如in
SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key1)
7.LEFT,RIGHT和FULL OUTER连接,以便提供对无条件匹配的ON子句的更多控制。例如,这个查询:
SELECT a.id,a.name,b.id,b.name from t_a a left JOIN t_b b on a.id=b.id;
SELECT a.id,a.name,b.id,b.name from t_a a right JOIN t_b b on a.id=b.id;
SELECT a.id,a.name,b.id,b.name from t_a a full JOIN t_b b on a.id=b.id;
8.LEFT SEMI JOIN:左半连接(只显示左表的数据)
SELECT a.key, a.value
FROM a
WHERE a.key in ( SELECT b.key FROM B );
可以写成:
SELECT a.key, a.val
FROM a
LEFT SEMI JOIN b ON (a.key = b.key)
9.【尽量使用EXISTS】IN / EXISTS,如果使用EXISTS,子查询没有,父查询不会执行;而IN父查询依然执行
SELECT *
FROM t_a a
WHERE id EXISTS (select id from t_b b where b.id = a.id);
10.【MAPJOIN】如果两张表在连接的列上都进行了“流式传输”,并且一个表中的桶数是另一个表中的桶数的倍数,那么可以使用MAPJOIN。
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a
JOIN b ON a.key = b.key
#注:MAPJOIN不是默认行为,并由以下参数控制
set hive.optimize.bucketmapjoin = true
11.【MAPJOIN】如果两张表在连接的列上都进行了“排序和分桶”,并且桶的数量一样,那么可以使用MAPJOIN。
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM A a
JOIN B b ON a.key = b.key
#注:这不是默认行为,需要设置以下参数:
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
12.【MAPJOIN限制】:以下情况不支持MAPJOIN
1.联合查询Union
2.横向视图Lateral View
3.Group By/Join/Sort By/Cluster By/Distribute By
4.MapJoin后面跟着Union
5.MapJoin后面跟着Join
6.MapJoin后面跟着MapJoin
优化:JOIN
https://cwiki.apache.org/conf...
联合:UNION
- 1.2.0之前:不会删除重复行
- 1.2.0之后:默认删除重复行,
- ALL:不删除重复行, DISTINCT:删除重复行
- 每个select_statement返回的列的数量和名称必须相同。否则,抛出架构错误。
https://cwiki.apache.org/conf...
1.UNION例子
select_statement
UNION ALL
select_statement
2.FROM中的UNION
SELECT u.id, actions.date
FROM (
SELECT av.uid AS uid
FROM action_video av
WHERE av.date = '2008-06-03'
UNION ALL
SELECT ac.uid AS uid
FROM action_comment ac
WHERE ac.date = '2008-06-03'
) actions JOIN users u ON (u.id = actions.uid)
3.列别名
语句1:错误
INSERT OVERWRITE TABLE target_table
SELECT name, id, category FROM source_table_1
UNION ALL
SELECT name, id, "Category159" FROM source_table_2
语句2:正确
INSERT OVERWRITE TABLE target_table
SELECT name, id, category FROM source_table_1
UNION ALL
SELECT name, id, "Category159" as category FROM source_table_2
4.列类型转换(和列别名差不多)
SELECT name, id, cast('2001-01-01' as date) d FROM source_table_1
UNION ALL
SELECT name, id, hiredate as d FROM source_table_2
取样:TABLESAMPLE
- 取样需要分桶
https://cwiki.apache.org/conf...
语法:
TABLESAMPLE (BUCKET x OUT OF y [ON colname])
x:第几桶,从1开始
y:总桶数
col:列
简单抽样:取第几桶数据
select * from t_buk tablesample(bucket 1 out of 3);
select * from t_buk tablesample(bucket 2 out of 3);
随机桶抽样:查询3桶中的第1桶,由于使用了rand(),会随机加桶。
select * from t_buk tablesample(bucket 1 out of 3 on rand());
select * from t_buk tablesample(bucket 2 out of 3 on rand());
固定桶抽样:取第几桶数据(实际效果和简单抽样一致)
select * from t_buk tablesample(bucket 1 out of 3 on id);
select * from t_buk tablesample(bucket 2 out of 3 on id);
压缩桶取样:取第几桶数据(所有桶的数据会根据桶的数量重新进行分配,n%2 )
select * from t_buk tablesample(bucket 1 out of 2 on id);
select * from t_buk tablesample(bucket 2 out of 2 on id);
拉伸桶取样:取第几桶数据(所有桶的数据会根据桶的数量重新进行分配,n%4 )
select * from t_buk tablesample(bucket 1 out of 4 on id);
select * from t_buk tablesample(bucket 2 out of 4 on id);
百分比取样:
select * from t_buk tablesample(10 percent); // 12*0.1 = 1.2,有余数则 +1
select * from t_buk tablesample(20 percent); // 12*0.2 = 2.4,
字节长度取样:
ByteLengthLiteral : (Digit)+ ('b' | 'B' | 'k' | 'K' | 'm' | 'M' | 'g' | 'G')
select * from t_buk tablesample(10b);
子查询:FROM、WHERE
- FROM的子查询
1.语法:
SELECT ... FROM (subquery) table_name ...
SELECT ... FROM (subquery) AS table_name ...
2.例子:
SELECT col
FROM (
SELECT a+b AS col
FROM t1
) t2
3.子查询包含UNION ALL的示例:
SELECT t3.col
FROM (
SELECT a+b AS col
FROM t1
UNION ALL
SELECT c+d AS col
FROM t2
) t3
- WHERE的子查询
1.例子:
SELECT *
FROM A
WHERE A.a IN (SELECT foo FROM B);
2.其他受支持的类型是EXISTS和NOT EXISTS子查询:
SELECT A
FROM T1
WHERE EXISTS (SELECT B FROM T2 WHERE T1.X = T2.Y)
虚拟列:Virtual Columns
虚拟列
Hive 0.8.0支持两个虚拟列:
一个是INPUT__FILE__NAME,它是mapper任务的输入文件名。
另一个是BLOCK__OFFSET__INSIDE__FILE,这是当前的全局文件位置。
对于块压缩文件,它是当前块的文件偏移量,它是当前块的第一个字节的文件偏移量。
从Hive 0.8.0开始,添加了以下虚拟列:
ROW__OFFSET__INSIDE__BLOCK
RAW__DATA__SIZE
ROW__ID
GROUPING__ID
需要注意的是,此处列出的所有虚拟列都不能用于任何其他目的(即,使用具有虚拟列的列创建表将失败,并显示“SemanticException错误10328:无效的列名...”)
简单的例子
从src中选择INPUT__FILE__NAME,键BLOCK__OFFSET__INSIDE__FILE;
按键INPUT__FILE__NAME按顺序从src组中选择键,count();
从src中选择*,其中BLOCK__OFFSET__INSIDE__FILE> 12000按键排序;
内置函数【0】:UDF
https://cwiki.apache.org/conf...
- 运算符
- 内置函数UDF
- 内置聚合函数UDAF
- 内置表生成函数UDTF
show functions
hive> show functions;
OK
!
!=
%
&
*
+
-
/
<
<=
<=>
<>
=
==
>
>=
^
abs
acos
add_months
and
array
array_contains
ascii
asin
assert_true
atan
avg
base64
between
bin
case
ceil
ceiling
coalesce
collect_list
collect_set
compute_stats
concat
concat_ws
context_ngrams
conv
corr
cos
count
covar_pop
covar_samp
create_union
cume_dist
current_database
current_date
current_timestamp
current_user
date_add
date_sub
datediff
day
dayofmonth
decode
default.row_num
degrees
dense_rank
div
e
elt
encode
ewah_bitmap
ewah_bitmap_and
ewah_bitmap_empty
ewah_bitmap_or
exp
explode
field
find_in_set
first_value
floor
format_number
from_unixtime
from_utc_timestamp
get_json_object
greatest
hash
hex
histogram_numeric
hour
if
in
in_file
index
initcap
inline
instr
isnotnull
isnull
java_method
json_tuple
lag
last_day
last_value
lcase
lead
least
length
like
ln
locate
log
log10
log2
lower
lpad
ltrim
map
map_keys
map_values
matchpath
max
min
minute
month
named_struct
negative
next_day
ngrams
noop
noopstreaming
noopwithmap
noopwithmapstreaming
not
ntile
nvl
or
parse_url
parse_url_tuple
percent_rank
percentile
percentile_approx
pi
pmod
posexplode
positive
pow
power
printf
radians
rand
rank
reflect
reflect2
regexp
regexp_extract
regexp_replace
repeat
reverse
rlike
round
row_number
rpad
rtrim
second
sentences
sign
sin
size
sort_array
space
split
sqrt
stack
std
stddev
stddev_pop
stddev_samp
str_to_map
struct
substr
substring
sum
tan
to_date
to_unix_timestamp
to_utc_timestamp
translate
trim
ucase
unbase64
unhex
unix_timestamp
upper
var_pop
var_samp
variance
weekofyear
when
windowingtablefunction
xpath
xpath_boolean
xpath_double
xpath_float
xpath_int
xpath_long
xpath_number
xpath_short
xpath_string
year
|
~
Function | Return Type | Argument Types | Description |
---|---|---|---|
unix_timestamp | timestamp | [date[, pattern]] | Returns the UNIX timestamp |
upper | string | string | Returns str Returns str with all characters changed to uppercase |
upper | |||
内置函数例子:
随机数:select rand();
随机0-100: select split(rand()*100,"\\.")[0];
四舍五入:
select round( rand()*100,0);
select round( rand()*100); //0-100,保留一位小数
select round( rand()*100,2); //0-100,保留2位小数
select substring(rand()*100,0,2); //截取0-2位
select substr(rand()*100,0,2);
select indexof(rang()*100,"."); //.的位置 ???
select locate(rand()*100,"."); ???
select regexp_replace("a.jpg","jpg","png"); //正则替换
select cast( 1 as double); //类型强制转换
字符串连接: CONCAT(), +
判断语句:
select tihuan
case
when 1=1 then "男"
when 1=2 then "女"
else "人妖"
end;
case vis.next_data_source
when 'IPM' then case vis.source_type when 'tvbar' then biz_ipm.name when 'subject' then subj_ipm.name when 'detail' then det_ipm.name end
when 'VIS' then case vis.source_type when 'tvbar' then biz.name when 'subject' then subj.name end
when 'playproxy' then case vis.source_type when 'tvbar' then biz.name when 'subject' then subj.name end
when 'EPG' then case vis.source_type when 'tvbar' then biz.name when 'subject' then subj.name end
end source_name,
case when hour(in_time) between 0 and 5 then 1 end 在xx到xx之间
SQL语句中的转换:查表u3的name和sex,如果sex为1,返回“男”;2返回“女”
select
u.name,
case u.sex when 1 then "男" when 2 then "女" else "人妖" end
from u3 u;
IF语句:
select if(1=1,"男","女");
和上面效果一样
select
u.name,
if(u.sex=1,"男",if(u.sex=2,"女","人妖"))
from u3 u;
select concat("1","2","3"); //连接字符串
select concat_ws("|","1","2","3"); //连接,带分隔符
select length("dasdadada"); //字符串长度
select size(array(1,2,3)); //数组个数
select current_date 当前时间:2019-07-11
select current_timestamp 当前时间:2019-07-11 15:28:49.499
cast('1214234321' as int)
cast('1214234321' as timestamp)
unix_timestamp(date/timestamp); 字符串转时间戳(数据库中的date、timestrap转毫秒时间戳)
unix_timestamp(date, format); 字符串转时间戳
###########
假如starttime在数据库中是以timestamp存储的: 显示2019-12-01 16:04:07.0
我们使用的时候将starttime转为我们在hive中可用的unix_timestamp
from_unixtime(date/timestamp) 时间戳转字符串date
from_unixtime(date/timestamp, format) 时间戳转字符串date
datediff(enddate, startdate) 获得相差天数,(date ,date) -> int
date_add(startdate, intdays) 获得增加后的时间 date -> date
date_sub(startdate, intdays) 获得减少后的时间 date -> date
date_format(date/timestamp/string, fmt) 时间格式化 date -> date
select datediff(current_date, '2019-01-01')
select datediff(date_format(current_date, '%Y-%m-%d'), '2019-07-10') //计算日期差
select datediff(MONTH,'2012/8/1','2012/8/20') as daysum //计算相差月数
select datediff(DAY,'2012/8/1','2012/8/20') as daysum //计算相差天数
select datediff(HOUR,'2012/8/1','2012/8/20') as daysum //计算相差小时数
select datediff(MINUTE,'2012/8/1','2012/8/20') as daysum //计算相差分钟数
select datediff(SECOND,'2012/8/1','2012/8/20') as daysum //计算相差秒数
//注解:MONTH为月、DAY为查询天、HOUR为小时、MINUTE为分钟、SECOND为秒
FROM_UNIXTIME
================================
timestamp > 时间字符串
hive> desc function from_unixtime;
from_unixtime(unix_time, format) - returns unix_time in the specified format date
参数:
时间戳timestamp
返回值格式:
'%Y-%m-%d %H:%i:%S'
'yyyy-MM-dd hh:ss:mm'
例如:
mysql>SELECT FROM_UNIXTIME( 1249488000, 'yyyyMMdd' ) ->20071120
mysql>SELECT FROM_UNIXTIME( 1249488000, '%Y年%m月%d' ) ->2007年11月20
from_unixtime(cast(t.update_time as bigint),'yyyy-MM-dd HH:mm:ss')
UNIX_TIMESTAMP
=================================
时间字符串/date/datetime/timestamp > timestamp
hive> desc function UNIX_TIMESTAMP;
UNIX_TIMESTAMP([date[, pattern]]) - Returns the UNIX timestamp
与from_unixtime相对正好相反的时间函数
若无参数调用,则返回一个 Unix timestamp ('1970-01-01 00:00:00' GMT 之后的秒数) 作为无符号整数。
若用date 来调用 UNIX_TIMESTAMP(),它会将参数值以'1970-01-01 00:00:00' GMT后的秒数的形式返回。date 可以是一个 DATE 字符串、一个 DATETIME字符串、一个 TIMESTAMP或一个当地时间的YYMMDD 或YYYMMDD格式的数字。
例如:
hive> SELECT UNIX_TIMESTAMP() 结果:1249524739
hive> SELECT UNIX_TIMESTAMP('2009-08-06') 结果:1249488000
hive> SELECT UNIX_TIMESTAMP( date() ) 结果:1249488000
hive> SELECT UNIX_TIMESTAMP( 1249488000 ) 结果:1249488000
1、如果hive表中是varchar
unix_timestamp("2020-01-01 12:30:54") -> 1249488000
2、如果hive表中是long
from_unixtime(dt*0.001, 'yyyy-MM-dd hh:ss:mm') -> 2020-01-01 12:30:54
bigint -> varchar: from_unixtime(visplaylog_datetime/1000) log_datetime
3、如果hive表中是timestamp
unix_timestamp(1249488000) -> 1249488000 (hive中和unix中的timestamp格式是不一样的,使用前必须先转化)
4、如果hive中的是date
unix_timestamp(date()) -> 1249488000
排序函数:UDF
- row_number(): 值相同,名次增加
- rank():值相同,并列,跳跃1224
- desen_rank(): 值相同,并列,不跳跃1223
数据:
01 gp1802 84
02 gp1801 84
03 gp1802 84
04 gp1802 84
05 gp1801 81
06 gp1802 81
07 gp1802 81
08 gp1801 81
09 gp1802 81
10 gp1802 81
11 gp1803 81
12 gp1802 89
13 gp1802 89
14 gp1802 89
15 gp1803 89
16 gp1802 91
17 gp1802 97
18 gp1802 72
建表
create table t_rank (
sid string,
class string,
score int
)
row format delimited
fields terminated by ' ';
导入数据:
load data local inpath '/home/rank.txt' into table t_rank;
1.5 需求:统计每个班级的每个学生成绩(学生成绩按照降序排列)
select * from t_rank group by class order by score; 不行的,分组查询要和聚合函数联用
e.g.
select class, sid, score,
row_number() over(distribute by class sort by score desc),
rank() over(distribute by class sort by score desc),
dense_rank() over(distribute by class sort by score desc)
from t_rank;
1.6 需求:统计每个班级成绩前三的同学有哪些
e.g.
select a.* from
(
select class, sid, score,
row_number() over(distribute by class sort by score desc) rank
from t_rank
) a
where rank <= 3;
自定义函数:UDF
UDF的evaluate方法的上下文是一次一行。
1、创建Maven项目
maven依赖pom.xml:
org.apache.hive
hive-exec
1.2.1
junit
junit
4.12
compile
2、创建java类,继承UDF
public class Birth2Age extends UDF {
/**
* 输入生日,返回年龄
*
* evaluate:方法名称必须是这个,但是可以重载
*
* @param birthage :格式为yyyy-MM-dd (eg.2018-08-08)
* @return
*/
public int evaluate(String birthage) throws ParseException {
if (birthage == null){
return 0;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date_bir = format.parse(birthage);
Calendar calendar_cur = Calendar.getInstance();
Date date_cur = new Date();
calendar_cur.setTimeInMillis(date_cur.getTime());
int year_cur = calendar_cur.get(Calendar.YEAR);
Calendar calendar_bir = Calendar.getInstance();
calendar_bir.setTimeInMillis(date_bir.getTime());
int year_bir = calendar_bir.get(Calendar.YEAR);
return year_cur-year_bir;
}
}
3、maven打包jar
package双击
4、jar包上传到hdfs
FileZilla..
5、将jar包添加在hive中
hive> add jar /home/udf.jar; 路径不加单引号
6、创建临时函数
语法:
CREATE TEMPORARY FUNCTION function_name AS class_name;
创建临时函数:
hive> create temporary function udf_to_upper as 'com.qf.udf.TOUpperCase'
删除临时函数:
DROP TEMPORARY FUNCTION [IF EXISTS] function_name;
7、创建永久函数
语法:
CREATE FUNCTION [db_name.]function_name AS class_name
[USING JAR|FILE|ARCHIVE 'file_uri' [, JAR|FILE|ARCHIVE 'file_uri'] ];
1.将jar包上传到hdfs任意位置
2.调用命令
hive>
CREATE FUNCTION udf_Birth2Age AS 'com.qf.Birth2Age'
USING JAR 'hdfs://y51:9000/udf_Birth2Age.jar';
CREATE FUNCTION udf_JsonSerDe AS 'org.openx.data.jsonserde.JsonSerDe'
USING JAR 'hdfs://y51:9000/home/json-serde-1.3.9-SNAPSHOT-jar-with-dependencies.jar';
删除函数:
hive> DROP FUNCTION udf_Birth2Age;
重新加载函数:
hive> RELOAD FUNCTION;
8、其它方式加载函数
0、配置jar目录
hive.aux.jars.path
$HIVE_HOME/auxlib/
1、单次使用
hive> add jar /home/udf.jar; 路径不加单引号
hive> CREATE TEMPORARY FUNCTION function_name AS class_name;
2、在任意目录创建hive-init文件,并添加如下内容
add jar /home/udf.jar;
CREATE TEMPORARY FUNCTION udf_toUpperCase AS 'cn.qphone.udf.UDF_ToUpperCase';
hive> hive -i hive-init (每次启动hive的时候手动执行一遍)
3、在hive的conf目录下创建.hiverc文件,并添加如下内容(在hive启动时会自动执行)
add jar /home/udf.jar;
CREATE TEMPORARY FUNCTION udf_toUpperCase AS 'cn.qphone.udf.UDF_ToUpperCase';
4、永久加载
参考7、创建永久函数
侧面视图(爆炸):Lateral View
https://cwiki.apache.org/conf...(array)
数组:explode (array):
explode将数组(或地图)作为输入,并将数组(map)的元素作为单独的行输出
数组:explode (array)
select explode(array('A','B','C'));
select explode(array('A','B','C')) as col;
select tf.* from (select 0) t lateral view explode(array('A','B','C')) tf;
select tf.* from (select 0) t lateral view explode(array('A','B','C')) tf as col;
col |
---|
A |
B |
C |
- 集合: explode (map)
集合: explode (map)
select explode(map('A',10,'B',20,'C',30));
select explode(map('A',10,'B',20,'C',30)) as (key,value);
select tf.* from (select 0) t lateral view explode(map('A',10,'B',20,'C',30)) tf;
select tf.* from (select 0) t lateral view explode(map('A',10,'B',20,'C',30)) tf as key,value;
key | value |
---|---|
A | 10 |
B | 20 |
C | 30 |
posexplode (array):
posexplode类似于explode`但它不是仅仅返回数组的元素,而是返回元素以及它在原始数组中的位置。
select posexplode(array('A','B','C'));
select posexplode(array('A','B','C')) as (pos,val);
select tf.* from (select 0) t lateral view posexplode(array('A','B','C')) tf;
select tf.* from (select 0) t lateral view posexplode(array('A','B','C')) tf as pos,val;
pos | val |
---|---|
0 | A |
1 | B |
2 | C |
1.6 分区分桶
1.1 什么是分区
1、为什么要使用分区?
在查询hive数据时,都是通过扫描目录中所有的文件,随着我们的文件数量越来越多,这会导致我们的查询效率越来越低。
2、什么是分区?
mapreduce中的分区是将不同的数据分别写入不同的【文件】中,而hive的分区则是一个目录,每个目录会将存放不同的数据。(例:将每年的数据分别存储在不同的目录下)
1.2 静态分区
需要手动指定分区列表
1.2.1 创建一级分区表
(1)创建分区表:
1.创建分区的时候必须指定一个分区列(站位列,不是真的列)
==============================================
create table t_part(
id int,
name string,
sex string,
money double
)
partitioned by(location string)
row format delimited
fields terminated by '\t';
create table t_part(
id int,
country string
)
partitioned by(location string)
row format delimited
fields terminated by '\t';
(2)一级分区导入数据:
==============================================
语法:
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
导入数据
load data local inpath '/home/user_china.txt' into table t_part partition(location='china')
load data local inpath '/home/user_japan.txt' into table t_part partition(location='japan')
1.2.2 创建二级分区表
create table t_part2(
id int,
name string,
sex string,
money double
)
partitioned by(year string, month string)
row format delimited
fields terminated by '\t'
stored as textfile;
(2)二级分区导入数据:
==============================================
语法:
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
导入数据
load data local inpath '/home/user-2019-01-12.txt' into table t_part2 partition(year='2019',month='01')
load data local inpath '/home/user-2019-11-11.txt' into table t_part2 partition(year='2019',month='11')
load data local inpath '/home/user-2019-12-12.txt' into table t_part2 partition(year='2019',month='12')
1.3 动态分区
会动态生成分区目录(动态分区会调用mapreduce执行分区操作,会消耗更多资源)
1.3.1 修改hive-site.xml
1、修改hive-site.xml
javax.jdo.option.ConnectionPassword
123456
javax.jdo.option.ConnectionURL
jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true
desc
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
javax.jdo.option.ConnectionUserName
root
hive.exec.mode.local.auto
true
hive.cli.print.current.db
true
、
hive.exec.dynamic.partition
true
hive.exec.dynamic.partition.mode
nonstrict
1.3.2 创建分区表
create table t_dynamic_part (
id int,
name string,
sex string,
money double
)
partitioned by(location string)
row format delimited
fields terminated by '\t';
1.3.3 动态分区导入数据
语法:
INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)];
导入数据:
insert into t_dynamic_part partition(location)
select * from t_part;
二、分桶
2.1 分桶如何提升性能
结论:避免笛卡尔积,大量减少运算次数。
table_1:
a 1
b 2
c 3
d 4
e 5
f 6
table_2:
1 xx
2 xx
3 xx
4 xx
5 xx
6 xx
分桶:(规则 n%3)
a 1 b 2 c 3
d 4 e 5 f 6
============================================
1 xx 2 xx 3 xx
4 xx 5 xx 6 xx
一般情况:当table_1和table_2进行join操作时,table_1会和table_2的每个数据进行匹配。
分桶之后:当table_1和table_2进行join操作时,table_1的第一个桶会和table_2的第一个桶进行join
原始计算次数:6*6=36
分桶后计算次数:2*2 + 2*2 + 2*2 = 12
2.2 创建分桶表
创建分桶表:
create table t_buk(
id int,
name string,
sex string,
money double
)
clustered by(id) sorted by(id asc) into 3 buckets
row format delimited
fields terminated by '\t';
导入数据:
1 lixi man 1000.0
2 lixi man 1000.0
3 lixi man 1000.0
4 lixi man 1000.0
5 lixi man 1000.0
6 lixi man 1000.0
7 lixi man 1000.0
8 lixi man 1000.0
9 lixi man 1000.0
10 lixi man 1000.0
11 lixi man 1000.0
12 lixi man 1000.0
insert into t_buk select * from t_part cluster by id; -- cluster自带全局排序
或
insert into t_buk select * from t_stu distribute by id sort by name asc, age desc; -- distribute可自定义
2.3 分桶查询
- Cluster by (在查询数据时,不能使用局部排序sort by)
- Distribute by ... sort by ... (sort局部排序,order by:全局排序)
语法(可用于数据导入):
SELECT col1, col2 FROM t_stu CLUSTER BY col1;
SELECT col1, col2 FROM t_stu DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC;
必须设置reduceTask个数(决定了分桶个数):
set mapreduce.job.reduces=3;
2.4 抽样查询
- tablesample
语法:
TABLESAMPLE (BUCKET x OUT OF y [ON colname])
x:第几桶,从1开始
y:总桶数
col:列
简单抽样:取第几桶数据
select * from t_buk tablesample(bucket 1 out of 3);
select * from t_buk tablesample(bucket 2 out of 3);
随机桶抽样:查询3桶中的第1桶,由于使用了rand(),会随机加桶。
select * from t_buk tablesample(bucket 1 out of 3 on rand());
select * from t_buk tablesample(bucket 2 out of 3 on rand());
固定桶抽样:取第几桶数据(实际效果和简单抽样一致)
select * from t_buk tablesample(bucket 1 out of 3 on id);
select * from t_buk tablesample(bucket 2 out of 3 on id);
压缩桶取样:取第几桶数据(所有桶的数据会根据桶的数量重新进行分配,n%2 )
select * from t_buk tablesample(bucket 1 out of 2 on id);
select * from t_buk tablesample(bucket 2 out of 2 on id);
拉伸桶取样:取第几桶数据(所有桶的数据会根据桶的数量重新进行分配,n%4 )
select * from t_buk tablesample(bucket 1 out of 4 on id);
select * from t_buk tablesample(bucket 2 out of 4 on id);
百分比取样:
select * from t_buk tablesample(10 percent); // 12*0.1 = 1.2,有余数则 +1
select * from t_buk tablesample(20 percent); // 12*0.2 = 2.4,
字节长度取样:
ByteLengthLiteral : (Digit)+ ('b' | 'B' | 'k' | 'K' | 'm' | 'M' | 'g' | 'G')
select * from t_buk tablesample(10b);
三、分区分桶结合
1.创建原始表(临时表)
分区列要放在最后位置
===========================================
create TEMPORARY table t_com(
id int,
name string,
money double,
sex int
)
row format delimited
fields terminated by '\t'
stored as textfile;
2、加载数据
===========================================
1 lixi 1000.0 1
2 lixi 1000.0 1
3 lixi 1000.0 1
4 lixi 1000.0 1
5 lixi 1000.0 1
6 lixi 1000.0 1
7 lixi 1000.0 1
8 lixi 1000.0 1
9 lixi 1000.0 1
10 lixi 1000.0 0
11 lixi 1000.0 0
12 lixi 1000.0 0
load data local inpath '/home/log.txt' into table t_com;
3、创建分桶分区表
===========================================
- 以sex性别分区(分区列是伪列,不写在里面)
- 分4桶
create table t_part_buk(
id int,
name string,
money double
)
partitioned by(sex int)
clustered by(id) sorted by(id asc) into 4 buckets
row format delimited
fields terminated by '\t'
stored as textfile;
create table t_buk(
id int,
country string
)
partitioned by(location string)
clustered by(id) sorted by(id asc) into 3 buckets
row format delimited
fields terminated by '\t'
stored as textfile;
4、导入数据
tip: 必须设置reduceTask个数(决定了分桶个数):set mapreduce.job.reduces=4;
===========================================
insert into t_part_buk partition(sex)
select id,country from t_com distribute by id sort by id asc;
5、查询结果:
===========================================
> select * from t_part_buk;
OK
12 lixi 1000.0 0
10 lixi 1000.0 0
11 lixi 1000.0 0
4 lixi 1000.0 1
8 lixi 1000.0 1
1 lixi 1000.0 1
5 lixi 1000.0 1
9 lixi 1000.0 1
2 lixi 1000.0 1
6 lixi 1000.0 1
3 lixi 1000.0 1
7 lixi 1000.0 1
每个区都会有4个桶
1.7 存储格式
Hive数据存储格式
https://cwiki.apache.org/conf...
Storage Formats
textfile:默认的存储格式;普通文本文件,数据不会压缩
sequencefile:hive提供的一种二进制存储格式,自带压缩,可以切割
rcfile:一种行列混合存储格式,会将相近的行与列放在一起,存储耗时,查询较快,自带压缩。
orc:是rcfile的一种优化
parquet:自定义输入输出格式
serde记录格式
1、常见的serde
ser:serialiler序列化
de:deserialilzer反序列化
csv、tsv、json serde、regex、parqut
2、创建csv格式的表
创建csv表:
create table csv1(
name string,
score string
)
row format serde 'org.apache.hive.serde2.OpenCSVSerde'
with serdeproperties(
"separatorChar"="|",
"quoteChar"="'",
"esacpeChar"="\\"
)
stored as textfile
;
导入数据:
LOAD DATA LOCAL INPATH '/HOME/CSV.txt' INTO TABLE csv1;
3、json serde
1.添加第三方jar包
hive> add jar /home/json-serde-1.3-jar-with-dependencies.jar;
2.创建表
create table json1(
name string,
score array
4、regex serde
创建表:
create table regex1(
host string,
dt string
)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties(
"input.regex"="^([0-9]{1,3}.[0-9]{1,3}.[0-9]{2,3} (.*)$)"
)
stored as textfile
;
导入数据:
192.168.120.100 [31/Jan/2012:00:02:02 +0800]
192.168.120.100 [31/Jan/2012:00:02:02 +0800]
192.168.120.100 [31/Jan/2012:00:02:02 +0800]
LOAD DATA LOCAL INPATH '/home/regex.txt' INTO TABLE regex1;
1.8、显示
Show Databases【显示所有数据库】
Show Tables/Views/Partitions/Indexes
Show Tables【显示所有表】
Show Views【显示所有视图】
Show Partitions【显示分区】
Show Create Table【显示建表语句】
Show Indexes【显示索引】
Show Functions【显示所有函数】
1.8.1 显示所有数据库
SHOW DATABASES
1.8.2 显示所有表
SHOW TABLES
1.8.3 显示表所有视图
SHOW VIEWS; -- show all views in the current database
SHOW VIEWS 'test_*'; -- show all views that start with "test_"
SHOW VIEWS '*view2'; -- show all views that end in "view2"
SHOW VIEWS LIKE 'test_view1|test_view2'; -- show views named either "test_view1" or "test_view2"
SHOW VIEWS FROM test1; -- show views from database test1
SHOW VIEWS IN test1; -- show views from database test1 (FROM and IN are same)
SHOW VIEWS IN test1 "test_*"; -- show views from database test2 that start with "test_"
1.8.4 显示表所有分区
SHOW PARTITIONS table_name;
1.8.5 显示表DDL语句
SHOW CREATE TABLE ([db_name.]table_name|view_name);
1.8.6 显示表所有索引
SHOW [FORMATTED] (INDEX|INDEXES) ON table_with_index [(FROM|IN) db_name];
1.8.7 显示所有函数
SHOW FUNCTIONS "a.*";
1.9 压缩
在Hive中对中间数据或最终数据做压缩,是提高数据吞吐量和性能的一种手段。对数据做压缩,可以大量减少磁盘的存储空间,比如基于文本的数据文件,可以将文件压缩40%或更多。同时压缩后的文件在磁盘间传输和I/O也会大大减少;当然压缩和解压缩也会带来额外的CPU开销,但是却可以节省更多的I/O和使用更少的内存开销。
1.9.1 压缩模式评价
评价标准:
- 压缩比:压缩比越高,压缩后文件越小,所以压缩比越高越好。
- 压缩时间:越快越好。
- 已经压缩的格式文件是否可以再分割:可以分割的格式允许单一文件由多个Mapper程序处理,可以更好的并行化。
1.9.2 压缩模式对比
- BZip2有最高的压缩比但也会带来更高的CPU开销,Gzip较BZip2次之。如果基于磁盘利用率和I/O考虑,这两个压缩算法都是比较有吸引力的算法。
- LZO和Snappy算法有更快的解压缩速度,如果更关注压缩、解压速度,它们都是不错的选择。 LZO和Snappy在压缩数据上的速度大致相当,但Snappy算法在解压速度上要较LZO更快。
- Hadoop的会将大文件分割成HDFS block(默认64MB)大小的splits分片,每个分片对应一个Mapper程序。在这几个压缩算法中 BZip2、LZO、Snappy压缩是可分割的,Gzip则不支持分割。
1.9.3 常见压缩格式
压缩方式 | 压缩后大小 | 压缩速度 | 是否可分割 |
---|---|---|---|
GZIP | 中 | 中 | 否 |
BZIP2 | 小 | 慢 | 是 |
LZO | 大 | 快 | 是 |
Snappy | 大 | 快 | 是 |
1.9.4 Hadoop编码解码
压缩格式 | 对应的编码/解码器 |
---|---|
DEFAULT | org.apache.hadoop.io.compress.DefaultCodec |
Gzip | org.apache.hadoop.io.compress.GzipCodec |
Bzip | org.apache.hadoop.io.compress.BzipCodec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec(中间压缩使用) |
Lzo | com.hadoop.compression.lzo.LzoCodec(中间压缩使用) |
1.9.5 什么是分割
在考虑如何压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持分割是很重要的。考虑存储在HDFS中的未压缩的文件,其大小为1GB,HDFS的块大小为64MB,所以该文件将被存储为16块,将此文件用作输入的MapReduce作业会创建1个输人分片(split,也称为“分块”。对于block,我们统一称为“块”。)每个分片都被作为一个独立map任务的输入单独进行处理。
现在假设,该文件是一个gzip格式的压缩文件,压缩后的大小为1GB。和前面一样,HDFS将此文件存储为16块。然而,针对每一块创建一个分块是没有用的,因为不可能从gzip数据流中的任意点开始读取,map任务也不可能独立于其他分块只读取一个分块中的数据。gzip格式使用DEFLATE来存储压缩过的数据,DEFLATE将数据作为一系列压缩过的块进行存储。问题是,每块的开始没有指定用户在数据流中任意点定位到下一个块的起始位置,而是其自身与数据流同步。因此,gzip不支持分割(块)机制。
在这种情况下,MapReduce不分割gzip格式的文件,因为它知道输入是gzip压缩格式的(通过文件扩展名得知),而gzip压缩机制不支持分割机制。因此一个map任务将处理16个HDFS块,且大都不是map的本地数据。与此同时,因为map任务少,所以作业分割的粒度不够细,从而导致运行时间变长。
1.9.6 中间压缩
hive.exec.compress.intermediate:默认该值为false,设置为true为激活中间数据压缩功能。HiveQL语句最终会被编译成Hadoop的Mapreduce job,开启Hive的中间数据压缩功能,就是在MapReduce的shuffle阶段对mapper产生的中间结果数据压缩。在这个阶段,优先选择一个低CPU开销的算法。
mapred.map.output.compression.codec:该参数是具体的压缩算法的配置参数,SnappyCodec比较适合在这种场景中编解码器,该算法会带来很好的压缩性能和较低的CPU开销。设置如下:
set hive.exec.compress.intermediate=true
set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
set mapred.map.output.compression.codec=com.hadoop.compression.lzo.LzoCodec;
1.9.7 最终压缩
hive.exec.compress.output:用户可以对最终生成的Hive表的数据通常也需要压缩。该参数控制这一功能的激活与禁用,设置为true来声明将结果文件进行压缩。
mapred.output.compression.codec:将hive.exec.compress.output参数设置成true后,然后选择一个合适的编解码器,如选择SnappyCodec。设置如下:
set hive.exec.compress.output=true
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
1.9.8 TETFILE使用压缩
- Hive数据表的默认格式,存储方式:行存储。
- 可以使用Gzip压缩算法,但压缩后的文件不支持split
- 在反序列化过程中,必须逐个字符判断是不是分隔符和行结束符,因此反序列化开销会比SequenceFile高几十倍。
建表语句:
${建表语句}
stored as textfile;
##########################################插入数据########################################
set hive.exec.compress.output=true; --启用压缩格式
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; --指定输出的压缩格式为Gzip
set mapred.output.compress=true;
set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec;
insert overwrite table textfile_table select * from T_Name;
1.9.9 SEQUENCEFILE使用压缩
- 压缩数据文件可以节省磁盘空间,但Hadoop中有些原生压缩文件的缺点之一就是不支持分割。支持分割的文件可以并行的有多个mapper程序处理大数据文件,大多数文件不支持可分割是因为这些文件只能从头开始读。Sequence File是可分割的文件格式,支持Hadoop的block级压缩。
- Hadoop API提供的一种二进制文件,以key-value的形式序列化到文件中。存储方式:行存储。
- sequencefile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,RECORD是默认选项,通常BLOCK会带来较RECORD更好的压缩性能。
- 优势是文件和hadoop api中的MapFile是相互兼容的
建表代码
${建表语句}
SORTED AS SEQUENCEFILE; --将Hive表存储定义成SEQUENCEFILE
##########################################插入数据########################################
set hive.exec.compress.output=true; --启用压缩格式
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; --指定输出的压缩格式为Gzip
set mapred.output.compression.type=BLOCK; --压缩选项设置为BLOCK
set mapred.output.compress=true;
set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec;
insert overwrite table textfile_table select * from T_Name;
1.9.10 RCFILE使用压缩
存储方式:数据按行分块,每块按列存储。结合了行存储和列存储的优点:
- 首先,RCFile 保证同一行的数据位于同一节点,因此元组重构的开销很低
- 其次,像列存储一样,RCFile 能够利用列维度的数据压缩,并且能跳过不必要的列读取
- 数据追加:RCFile不支持任意方式的数据写操作,仅提供一种追加接口,这是因为底层的 HDFS当前仅仅支持数据追加写文件尾部。
- 行组大小:行组变大有助于提高数据压缩的效率,但是可能会损害数据的读取性能,因为这样增加了 Lazy 解压性能的消耗。而且行组变大会占用更多的内存,这会影响并发执行的其他MR作业。 考虑到存储空间和查询效率两个方面,Facebook 选择 4MB 作为默认的行组大小,当然也允许用户自行选择参数进行配置。
建表代码
${建表语句}
stored as rcfile;
-插入数据操作:
set hive.exec.compress.output=true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
set mapred.output.compress=true;
set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec;
insert overwrite table rcfile_table select * from T_Name;
1.9.11 ORC使用压缩
存储方式:数据按行分块,每块按照列存储。
压缩快,快速列存取。效率比rcfile高,是rcfile的改良版本。
1.9.12 压缩小结
- TextFile默认格式,加载速度最快,可以采用Gzip进行压缩,压缩后的文件无法split,即并行处理。
- SequenceFile压缩率最低,查询速度一般,将数据存放到sequenceFile格式的hive表中,这时数据就会压缩存储。三种压缩格式NONE,RECORD,BLOCK。是可分割的文件格式。
- RCfile压缩率最高,查询速度最快,数据加载最慢。
- 相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势。
- 在hive中使用压缩需要灵活的方式,如果是数据源的话,采用RCFile+bz或RCFile+gz的方式,这样可以很大程度上节省磁盘空间;而在计算的过程中,为了不影响执行的速度,可以浪费一点磁盘空间,建议采用RCFile+snappy的方式,这样可以整体提升hive的执行速度。至于lzo的方式,也可以在计算过程中使用,只不过综合考虑(速度和压缩比)还是考虑snappy适宜。
https://blog.csdn.net/xsdxs/a...
压缩 compression
1.9.1 map阶段的压缩
set hive.exec.compress.output=false
set hive.exec.compress.intermediate=false
set hive.intermediate.compression.codec
set hive.intermediate.compression.type
1.9.2 reduce阶段的压缩
set hive.exec.compress.output=false
set hive.exec.compress.intermediate=false
set hive.intermediate.compression.codec
set hive.intermediate.compression.type
1.9.3 自定义压缩
INPUTFORMAT and OUTPUTFORMAT
in the file_format to specify the name of a corresponding InputFormat and OutputFormat class as a string literal.
For example, 'org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextInputFormat'.
For LZO compression, the values to use are
'INPUTFORMAT "com.hadoop.mapred.DeprecatedLzoTextInputFormat"
OUTPUTFORMAT "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat"'
(see LZO Compression).
在file_format中指定相应的InputFormat和OutputFormat类的名称作为字符串文本。
例如,“org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextInputFormat”。
对于LZO压缩,要使用的值是
INPUTFORMAT“com.hadoop.mapred.DeprecatedLzoTextInputFormat”
OUTPUTFORMAT“org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat”
(见LZO压缩)。
1.9.4 压缩比例
压缩算法 | TEXTFILE | SEQUENCFILE | RCFILE | ORC |
---|---|---|---|---|
不压缩 | 119.2G | 54.1G | 20.0G | 98G |
snappy | 30.2G | 23.6G | 13.6G | 27.0G |
Gzip | 18.8G | 14.1G | 不支持 | 15.2G |
ZLIB | 不支持 | 不支持 | 10.1G | 不支持 |
1.10 窗口函数
1.10.1 SUM OVER
现有 hive 表 cookie1, 内容如下:
hive> select * from cookie1;
cookie1 2015-04-10 1
cookie1 2015-04-11 5
cookie1 2015-04-12 7
cookie1 2015-04-13 3
cookie1 2015-04-14 2
cookie1 2015-04-15 4
cookie1 2015-04-16 4
(1)对某个字段全部数据进行累加例如,求cookie1的总pv值
- partition by cookieid : 按照cookieid分组
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid) as sum1
from cookie1;
结果:
cookie1 2015-04-16 4 26
cookie1 2015-04-15 4 26
cookie1 2015-04-14 2 26
cookie1 2015-04-13 3 26
cookie1 2015-04-12 7 26
cookie1 2015-04-11 5 26
cookie1 2015-04-10 1 26
(2) 从第一行开始累加到当前行
select cookieid, createtime, pv,
sum(pv) over(partition by cookieid order by createtime) as sum2
from cookie1;
或:以上SQL语句是下面这个SQL语句的简写:
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as sum3
from cookie1;
# 结果
cookie1 2015-04-10 1 1
cookie1 2015-04-11 5 6
cookie1 2015-04-12 7 13
cookie1 2015-04-13 3 16
cookie1 2015-04-14 2 18
cookie1 2015-04-15 4 22
cookie1 2015-04-16 4 26
基本的语法是:
unbounded : 无限
preceding : 往前
following : 往后
between...end... : 指定操作的范围
current row : 当前行,计算到哪一行就是哪一行
between unbounded preceding and current row : 从起点到当前行,往前(对应表中的从上到下的顺序)累加
默认就是从起点到当前行往前累加,所以between unbounded preceding and current row这个条件可以不写。
##################################################
ROWS BETWEEN 1 AND 2 (从行1到行2)
ROWS BETWEEN 2 preceding AND 3 following (前2行 到 后3行)
ROWS BETWEEN 2 preceding AND current row (前2行 到 当前行)
ROWS BETWEEN unbounded preceding AND current row (第一行 到 当前行)
ROWS BETWEEN current row AND unbounded following (当前行 到 最后一行)
时间点分别可以是以当前行作为参考系,前面几行n PRECEDING或者是后面几行n FOLLOWING,也可以是当前行CURRENT ROW。总之可以想象有一个滑动窗口,我们可以规定一个滑动窗口的中心位置和大小,然后每次画过一个步长,计算一次窗口内的值。
(3) 计算分组内当前行到剩余所有行的和
select cookieid, createtime, pv,
sum(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as sum4
from cookie1;
结果分析 :
cookie1 2015-04-10 1 26 (1+5+7+3+2+4+4=26)
cookie1 2015-04-11 5 25 (5+7+3+2+4+4=25)
cookie1 2015-04-12 7 20 (7+3+2+4+4=20)
cookie1 2015-04-13 3 13 (3+2+4+4=13)
cookie1 2015-04-14 2 10 (2+4+4=10)
cookie1 2015-04-15 4 8 (4+4=8)
cookie1 2015-04-16 4 4 (4)
(4) 指定计算的范围
select cookieid, createtime, pv,
sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as sum5
from cookie1;
结果分析 :
cookie1 2015-04-10 1 1 (这一行前面没有记录,只能取本身的值)
cookie1 2015-04-11 5 6 (这一行前面有1,不够取3行的值,只能取一行与本身相加,取5+1=6)
cookie1 2015-04-12 7 13 (这一行前面有1,5,不够取3行的值,只能取两行与本身相加,取7+5+1=13)
cookie1 2015-04-13 3 16 (这一行前面有3行可以取,依次往回取三行,取3+7+5+1=16)
cookie1 2015-04-14 2 17 (同理,取2+3+7+5=17)
cookie1 2015-04-15 4 16 (同理,取4+2+3+7=16)
cookie1 2015-04-16 4 13 (同理,取4+4+2+3=13)
select cookieid, createtime, pv,
sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as sum6
from cookie1;
结果分析 :
cookie1 2015-04-10 1 6 (这一行前面没有记录,后面可以取一条记录,1+5=6)
cookie1 2015-04-11 5 13 (这一行前面只能取一条记录,后面可以取一条记录,1+5+7=13)
cookie1 2015-04-12 7 16 (这一行前面只能取两条记录,后面可以取一条记录,1+5+7+3=16)
cookie1 2015-04-13 3 18 (这一行前面可以取三条记录,后面可以取一条记录,1+5+7+3+2=18)
cookie1 2015-04-14 2 21 (同理,5+7+3+2+4=21)
cookie1 2015-04-15 4 20 (同理,7+3+2+4+4=20)
cookie1 2015-04-16 4 13 (这一行前面可以取三条记录,后面没有记录,3+2+4+4=13)
1.10.2 MIN OVER
sum、avg、max、min这些窗口函数的语法都是一样的,以下用一个SQL语句来演示 :
select cookieid, createtime, pv,
min(pv) over(partition by cookieid) as min1,
min(pv) over(partition by cookieid order by createtime) as min2,
min(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as min3,
min(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as min4,
min(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as min5,
min(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as min6
from cookie1;
结果 :
cookie1 2015-04-10 1 1 1 1 1 1 1
cookie1 2015-04-11 5 1 1 1 2 1 1
cookie1 2015-04-12 7 1 1 1 2 1 1
cookie1 2015-04-13 3 1 1 1 2 1 1
cookie1 2015-04-14 2 1 1 1 2 2 2
cookie1 2015-04-15 4 1 1 1 4 2 2
cookie1 2015-04-16 4 1 1 1 4 2 2
1.10.3 MAX OVER
select cookieid,createtime,pv,
max(pv) over(partition by cookieid) as max1,
max(pv) over(partition by cookieid order by createtime) as max2,
max(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as max3,
max(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as max4,
max(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as max5,
max(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as max6
from cookie1;
结果 :
cookie1 2015-04-10 1 7 1 1 7 1 5
cookie1 2015-04-11 5 7 5 5 7 5 7
cookie1 2015-04-12 7 7 7 7 7 7 7
cookie1 2015-04-13 3 7 7 7 4 7 7
cookie1 2015-04-14 2 7 7 7 4 7 7
cookie1 2015-04-15 4 7 7 7 4 7 7
cookie1 2015-04-16 4 7 7 7 4 4 4
1.10.4 AVG OVER
select cookieid,createtime,pv,
avg(pv) over(partition by cookieid) as avg1,
avg(pv) over(partition by cookieid order by createtime) as avg2,
avg(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as avg3,
avg(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as avg4,
avg(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as avg5,
avg(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as avg6
from cookie1;
结果 :
cookie1 2015-04-10 1 3.7142857142857144 1.0 1.0 3.7142857142857144 1.0 3.0
cookie1 2015-04-11 5 3.7142857142857144 3.0 3.0 4.166666666666667 3.0 4.333333333333333
cookie1 2015-04-12 7 3.7142857142857144 4.333333333333333 4.333333333333333 4.0 4.333333333333333 4.0
cookie1 2015-04-13 3 3.7142857142857144 4.0 4.0 3.25 4.0 3.6
cookie1 2015-04-14 2 3.7142857142857144 3.6 3.6 3.3333333333333335 4.25 4.2
cookie1 2015-04-15 4 3.7142857142857144 3.6666666666666665 3.6666666666666665 4.0 4.0 4.0
cookie1 2015-04-16 4 3.7142857142857144 3.7142857142857144 3.7142857142857144 4.0 3.25 3.25
1.10.5 ROW_NUMBER OVER
row_number(): 值相同,名次增加
1.10.6 RANK OVER
rank():值相同,并列,跳跃2225
1.10.7 DENSE_RANK OVER
desen_rank(): 值相同,并列,不跳跃2223
1.10.8 LAG OVER
这两个函数为常用的窗口函数,可以返回上下数据行的数据.
以我们的订单表为例,假如我们想要查看顾客上次的购买时间可以这样去查询
SQL
=================================================
select name,orderdate,cost,
lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1,
lag(orderdate,2) over (partition by name order by orderdate) as time2
from t_window;
查询后的数据为:
=================================================
name orderdate cost time1 time2
jack 2015-01-01 10 1900-01-01 NULL
jack 2015-01-05 46 2015-01-01 NULL
jack 2015-01-08 55 2015-01-05 2015-01-01
jack 2015-02-03 23 2015-01-08 2015-01-05
jack 2015-04-06 42 2015-02-03 2015-01-08
mart 2015-04-08 62 1900-01-01 NULL
mart 2015-04-09 68 2015-04-08 NULL
mart 2015-04-11 75 2015-04-09 2015-04-08
mart 2015-04-13 94 2015-04-11 2015-04-09
总结:
=================================================
time1取的为按照name进行分组,分组内升序排列,取上一行数据的值.
time2取的为按照name进行分组,分组内升序排列,取上面2行的数据的值,注意当lag函数为设置行数值时,默认为1行.未设定取不到时的默认值时,取null值.
lead函数与lag函数方向相反,取向下的数据.
1.10.9 LEAD OVER
lead函数与lag函数方向相反,取向下的数据.
1.10.10 FIRST_VALUE OVER
first_value取分组内排序后,截止到当前行,第一个值
last_value取分组内排序后,截止到当前行,最后一个值
SQL
================================================
select name,orderdate,cost,
first_value(orderdate) over(partition by name order by orderdate) as time1,
last_value(orderdate) over(partition by name order by orderdate) as time2
from t_window
查询结果如下:
================================================
name orderdate cost time1 time2
jack 2015-01-01 10 2015-01-01 2015-01-01
jack 2015-01-05 46 2015-01-01 2015-01-05
jack 2015-01-08 55 2015-01-01 2015-01-08
jack 2015-02-03 23 2015-01-01 2015-02-03
jack 2015-04-06 42 2015-01-01 2015-04-06
mart 2015-04-08 62 2015-04-08 2015-04-08
mart 2015-04-09 68 2015-04-08 2015-04-09
mart 2015-04-11 75 2015-04-08 2015-04-11
mart 2015-04-13 94 2015-04-08 2015-04-13
1.10.11 LAST_VALUE OVER
first_value取分组内排序后,截止到当前行,第一个值
last_value取分组内排序后,截止到当前行,最后一个值
SQL
================================================
select name,orderdate,cost,
first_value(orderdate) over(partition by name order by orderdate) as time1,
last_value(orderdate) over(partition by name order by orderdate) as time2
from t_window
查询结果如下:
================================================
name orderdate cost time1 time2
jack 2015-01-01 10 2015-01-01 2015-01-01
jack 2015-01-05 46 2015-01-01 2015-01-05
jack 2015-01-08 55 2015-01-01 2015-01-08
jack 2015-02-03 23 2015-01-01 2015-02-03
jack 2015-04-06 42 2015-01-01 2015-04-06
mart 2015-04-08 62 2015-04-08 2015-04-08
mart 2015-04-09 68 2015-04-08 2015-04-09
mart 2015-04-11 75 2015-04-08 2015-04-11
mart 2015-04-13 94 2015-04-08 2015-04-13
1.10.12 GROUPING SET, CUBE, ROLL UP
待补充
+-----------+------------+-----------+------------+
|data_source|play_type_id|pay_type_id|GROUPING__ID|
+-----------+------------+-----------+------------+
| playproxy| 2| 10| 0|
| VIS| 1| 10| 0|
| playproxy| 1| 10| 0|
| VIS| 3| 10| 0|
| VIS| 1| 10| 0|
| IPM| 1| 10| 0|
| playproxy| 1| 10| 0|
| VIS| 1| null| 2|
| VIS| 1| null| 2|
| playproxy| 2| null| 2|
| VIS| 3| null| 2|
| playproxy| 1| null| 2|
| playproxy| 1| null| 2|
| IPM| 1| null| 2|
| IPM| null| 10| 4|
| playproxy| null| 10| 4|
| VIS| null| 10| 4|
| VIS| null| 10| 4|
| playproxy| null| 10| 4|
| IPM| null| null| 6|
| playproxy| null| null| 6|
| playproxy| null| null| 6|
| VIS| null| null| 6|
| VIS| null| null| 6|
| null| 1| 10| 8|
| null| 3| 10| 8|
| null| 1| 10| 8|
| null| 2| 10| 8|
| null| 1| 10| 8|
| null| 2| null| 10|
| null| 3| null| 10|
| null| 1| null| 10|
| null| 1| null| 10|
| null| 1| null| 10|
| null| null| 10| 12|
| null| null| 10| 12|
| null| null| 10| 12|
| null| null| null| 14|
| null| null| null| 14|
| null| null| null| 14|
+-----------+------------+-----------+------------+
1 2 3 x
1 2 x
1 3 x
1 x
2 3 x
2 x
3 x
x
1 2 x
1 x
2 x
x
1.11 HIVE优化
1.11.1 设置map和reducer个数
一、 控制hive任务中的map数:
- 通常情况下,作业会通过input的目录产生一个或者多个map任务。
主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M, 可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改); - 举例:
a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数
b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数
即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。 - 是不是map数越多越好?
答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,
而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。
而且,同时可执行的map数是受限的。 - 是不是保证每个map处理接近128m的文件块,就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,
如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;
如何合并小文件,减少map数?
假设一个SQL任务:
Select count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04’;
该任务的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04
共有194个文件,其中很多是远远小于128m的小文件,总大小9G,正常执行会用194个map任务。
Map总共消耗的计算资源: SLOTS_MILLIS_MAPS= 623,020
我通过以下方法来在map执行前合并小文件,减少map数:
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
再执行上面的语句,用了74个map任务,map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
对于这个简单SQL任务,执行时间上可能差不多,但节省了一半的计算资源。
大概解释一下,100000000表示100M, set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并,
前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),
进行合并,最终生成了74个块。
如何适当的增加map数
当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
假设有这样一个任务:
Select data_desc,
count(1),
count(distinct id),
sum(case when …),
sum(case when ...),
sum(…)
from a group by data_desc
如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,
这样就可以用多个map任务去完成。
set mapred.reduce.tasks=10;
create table a_1 as
select * from a
distribute by rand(123);
这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。
每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。
看上去,貌似这两种有些矛盾,一个是要合并小文件,一个是要把大文件拆成小文件,这点正是重点需要关注的地方,
根据实际情况,控制map数量需要遵循两个原则:使大数据量利用合适的map数;使单个map任务处理合适的数据量;
1.11.2 控制hive任务的reduce数:
Hive自己如何确定reduce数:
reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定:
hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G)
hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)
即,如果reduce的输入(map的输出)总大小不超过1G,那么只会有一个reduce任务;
如:select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;/group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04 总大小为9G多,因此这句有10个reduce
- 调整reduce个数方法一:
调整hive.exec.reducers.bytes.per.reducer参数的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 这次有20个reduce - 调整reduce个数方法二;
set mapred.reduce.tasks = 15;
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;这次有15个reduce - reduce个数并不是越多越好;
同map一样,启动和初始化reduce也会消耗时间和资源;
另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题; - 什么情况下只有一个reduce;
很多时候你会发现任务中不管数据量多大,不管你有没有设置调整reduce个数的参数,任务中一直都只有一个reduce任务;
其实只有一个reduce任务的情况,除了数据量小于hive.exec.reducers.bytes.per.reducer参数值的情况外,还有以下原因:
a) 没有group by的汇总,比如把select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 写成 select count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04';
这点非常常见,希望大家尽量改写。
b) 用了Order by
c) 有笛卡尔积
通常这些情况下,除了找办法来变通和避免,我暂时没有什么好的办法,因为这些操作都是全局的,所以hadoop不得不用一个reduce去完成;
同样的,在设置reduce个数的时候也需要考虑这两个原则:使大数据量利用合适的reduce数;使单个reduce任务处理合适的数据量;
优化参考; https://www.cnblogs.com/wuxia...
1.11.1 mapreduce的基本流程及阶段可进行的优化操作
附上网上的一张老图(虽然老但是很具有代表性,哈哈哈) ,上面的图知道,对于mapreduce任务可分为以上几个步骤,input、splitting、Mapping、Shuffing、reducing、finalresult,我们可以对这些阶段进行分别的优化!!
Splitting阶段优化:将输入数据进行按照大小节分,分成不同的块
优化点:1.适当增加切割块的大小(单个节点先按照maxsize进行切分,剩下的进行minsize大小的合并。然后是节点之间的合并,最后是机架之间的合并。)
set mapreduce.input.fileinputformat.split.minsize = 1024000000;
set mapreduce.input.fileinputformat.split.maxsize = 1024000000;(默认256M)
set mapreduce.input.fileinputformat.split.minsize.per.node= 1024000000;
set mapreduce.input.fileinputformat.split.maxsize.per.node= 1024000000;(默认1b)
set mapreduce.input.fileinputformat.split.minsize.per.rack= 1024000000;
set mapreduce.input.fileinputformat.split.maxsize.per.rack= 1024000000;(默认1b)
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;(默认存在)
Mapping阶段优化:将相同的key进行对应的转换,其实map的个数取决于上一阶段切割的最终的数据块个数
优化点:1.手动规定map的个数(例子:任务中有100个map,但是可以使map分批执行一批10个)
set mapreduce.job.running.map.limit=20;
2.规定map同时并行的个数(例子:任务中有100个map,但是可以使map分批执行一批10个)
set mapreduce.map.memory.mb=3584;(3.5G内存) 默认2.1倍会杀掉
3.限制map可使用的最大内存
set hive.map.aggr = true
set hive.groupby.mapaggr.checkinterval = 100000(将数据每100000进行聚合)
Shuffing阶段优化:将相同的的key放到一个reduce中,其实是一个网络传输的过程。
优化点:1.map后进行压缩(压缩后自动解压)
set mapreduce.map.output.compress=true(map输出压缩,mapreduce参数)
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.GzipCodec(map输出压缩格式,mapreduce参数)
2.map后进行合并文件操作
set hive.merge.mapfiles = true(新启一个job完成合并,合并多大set hive.merge.size.per.task决定)
reducing阶段优化:进行数据累加操作,并将结果传输到对应的文件中。
优化点:1.手动规定reduce的个数
set mapred.reduce.tasks = 20;
2.规定reduce同时并行的个数(例子:任务中有100个reduce,但是可以使reduce分批执行一批10个)
set mapreduce.job.running.reduce.limit=80;
3.限制reduce可使用的最大内存
set mapreduce.reduce.memory.mb=7168;(7G内存) 默认2.1倍会杀掉
4.设置每个reduce可处理的数据大小(直接决定reduce个数)
set hive.exec.reducers.bytes.per.reducer=1024*1000*1000;
5.reduce最大个数
set hive.exec.reducers.max =2000;(mapreduce.job.running.reduce.limit变相使用)
6.reduce后可进行文件合并
set hive.merge.sparkfiles = false(spark引擎,结束后合并文件,新启动一个任务)
set hive.merge.tezfiles = false(tez引擎,结束后合并文件,新启动一个任务)
set hive.merge.mapredfiles = true(mapreduce引擎,结束后合并文件,新启动一个任务)
set hive.merge.smallfiles.avgsize =100*1000*1000 (输出文件小于当前值的时候,任务结束后合并文件的大小)
set hive.merge.size.per.task = 1024*1000*1000 (将文件合并成为多大)
finalresult阶段优化:其实就是写文件的过程。
优化点:1.reduce后要进行压缩写到HDFS(每个节点单独跑任务,但是最后的结果需要汇聚到一处)
set mapreduce.output.fileoutputformat.compress=false // 默认值是 false reduce属性
set mapreduce.output.fileoutputformat.compress.type=BLOCK // 默认值是 Record reduce属性
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec
其他优化:
JVM优化:一个JVM运行的job数是有上限的,我们可以设置最大执行的个数
set mapreduce.job.jvm.numtasks=100
并发及并发线程数优化:job的子查询可能没关系,所以可以开启并发查询
set hive.exec.parallel = true;
set hive.exec.parallel.thread.number=8;
数据倾斜优化:可进行key值个数的判断,判断时候发生数据倾斜
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000;(超过10000个相同的key就认为是数据倾斜,需要进行打散处理)
分区优化:hive有桶表和分区表,可开启动态分区(其实就是不同文件夹)
set hive.exec.dynamic.partition=true
set hive.exec.dynamic.partition.mode=nonstrict(分区表分为严格模式和非严格模式)
job之间优化:
set hive.exec.compress.output=true;(最终结果压缩。若map压缩和reduce压缩都没有用,改参数使用的话。两个job第一个job后数据不压缩,第二个job输出压缩)
set hive.exec.compress.intermediate=true(若map压缩reduce压缩最终输出压缩都没有用,改参数使用的话。两个job第一个job后数据压缩,第二个job输出不压缩) SQL优化:
小表往前放
1.11.2 常用hive参数优化
其实上面是对每一个阶段都进行数据优化,有很多参数都是默认开启或者有默认值的。
只需要用到常用的几个就行,其他的作为了解。下面列举出比较常用的:
其实上面是对每一个阶段都进行数据优化,有很多参数都是默认开启或者有默认值的。
只需要用到常用的几个就行,其他的作为了解。下面列举出比较常用的:
Splitting阶段:将输入小文件合并成为大文件
set mapreduce.input.fileinputformat.split.minsize = 1024000000;(参数mapreduce.map.memory.mb=3584 默认2.1倍会杀掉,一个map申请3.5G内存不用浪费了)
set mapreduce.input.fileinputformat.split.maxsize = 1024000000;
set mapreduce.input.fileinputformat.split.minsize.per.node= 1024000000;
set mapreduce.input.fileinputformat.split.maxsize.per.node= 1024000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack= 1024000000;
set mapreduce.input.fileinputformat.split.maxsize.per.rack= 1024000000;
map阶段一般很快,参数可以不设置
reduce阶段
set mapreduce.job.running.reduce.limit=80;(例子:任务中有100个reduce,但是可以使reduce分批执行一批10个)
合并文件
hive合并文件是新启动一个任务合并文件,感觉这个参数不太合适,有这个时间不如直接输出(map和reduce阶段都是一样的)。
压缩文件
(这个参数十分好,压缩不仅仅节约空间而且在网络传输的时候比较省宽带,mapreduce和spark都是默认可以解压缩的,比较方便。)
set mapreduce.map.output.compress=true(map输出压缩,map阶段参数)
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.GzipCodec(map输出压缩格式,map阶段参数)
set mapreduce.output.fileoutputformat.compress=false // 默认值是 false reduce阶段参数
set mapreduce.output.fileoutputformat.compress.type=BLOCK // 默认值是 Record reduce阶段参数
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec
set hive.exec.compress.output=true;(最终结果压缩。若map压缩和reduce压缩都没有用,改参数使用的话。两个job第一个job后数据不压缩,第二个job输出压缩)
set hive.exec.compress.intermediate=true(若map压缩reduce压缩最终输出压缩都没有用,改参数使用的话。两个job第一个job后数据压缩,第二个job输出不压缩)
Jvm优化(建议不设置)
并发优化
set hive.exec.parallel = true;
set hive.exec.parallel.thread.number=8;
数据倾斜优化:
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000;(超过10000个相同的key就认为是数据倾斜,需要进行打散处理)
分区优化(建表的时候要partation by ):
set hive.exec.dynamic.partition=true
set hive.exec.dynamic.partition.mode=nonstrict(分区表分为严格模式和非严格模式)
SQL优化
小表往前放
1.11.3 hivesql内存计算过程,mapreduce确定及常用UI端口
1.hive参数配置
Hive UI------>>>>Hive Configuration页签找到(版本与版本之间参数的名字不太一样一定要看清楚配置的名字,最好使用最新的配置名称)
2.hivesql使用内存资源
hivesql使用资源可在YARN的管理界面中RUNNING中看到,需要时不时刷新因为是动态的。(一般为3.5gmap个数字+7greduce个数)
3.hivesql生成的job的map个数reduce个数
可在YARN的管理界面中FINISHED中找到job后点击History,进去之后就会看到map数和reduce数
Splitting块个数决定map个数,reduce个数取决于输出的大小(1G一个reduce)
4.常用UI:
1、HDFS页面:50070
2、YARN的管理界面:8088
3、HistoryServer的管理界面:19888
4、Zookeeper的服务端口号:2181
5、Hive.server2=10002
6、Kafka的服务端口号:9092
7、Hbase界面:16010,60010
8、Spark的界面:8080