hive基础与高级查询
1.数据库和数据仓库
1.1 数据仓库
- 什么是数据仓库
数据仓库(Data Warehouse),可简写为DW或DWH,数据仓库,是为了企业所有级别的决策制定计划过程,提供所有类型数据类型的战略集合。它出于分析性报告和决策支持的目的而创建。为需要业务智能的企业 ,为需要指导业务流程改进、监视时间,成本,质量以及控制等;
也可以说,数据仓库就是面向分析的存储系统 - 数据仓库的特点
- 数据仓库是面向主题的
数据仓库是通过一个个主题,将多个业务系统的数据加载在一起,为了各个主题(如:用户、订单、商品)进行分析而建 - 数据仓库是集成的。
数据仓库的数据是从原来的分散的数据库数据(mysql等关系型数据库)抽取出来的。数据进入数据仓库之前,必然要经过统一与综合,这一步是数据仓库建设中最关键,最复杂的一步 - 数据仓库的数据是随着时间的变化而变化的
数据仓库中的数据不可更新是针对应用来说的,也就是说,数据仓库的用户进行分析处理是不进行数据更新操作的。数据仓库随着时间变化不断增加新的数据内容,数据库随着时间变化不断删去旧的数据内容 - 数据仓库的数据是不可修改的
数据仓库的数据一般都是历史数据,主要提供企业决策分析之用,所涉及的数据操作主要是数据查询。因为是保存的相当长的一段时间的数据,所以很少进行删除和更新。但是会定期更新和加载数据
- 数据仓库是面向主题的
1.2 数据库和数据仓库的区别
- 数据仓库是在数据库已经大量存在的情况下,为了进一步挖掘数据资源,为了决策而产生的
- 数据库与数据仓库的区别实际讲的是OLTP与OLAP的区别。
- 操作型处理,叫联机事务处理OLTP(On-Line Transaction Processing),也可以称面向交易的处理系统,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据的安全性、完整性和并发的支持用户数等问题。传统的数据库系统作为数据管理的主要手段,主要用于操作型处理。
- 分析型处理,叫联机分析处理OLAP(On-Line Analytical Processing)一般针对某些主题历史数据进行分析,支持管理决策。
- 数据库是面向事务的设计,数据仓库是面向主题设计的。
- 数据库一般存储在线交易数据,数据仓库存储的一般是历史数据。
- 数据库设计是尽量避免冗余,一般采用符合范式的规则来设计,数据仓库在设计是有意引入冗余,采用反范式的方式来设计。
- 数据库是为捕获数据而设计,数据仓库是为分析数据而设计。
1.3 数据仓库的分层架构
按数据流入流出的过程,数据仓库可以分为三层—元数据、数据仓库、数据应用
- 元数据层(ODS):
它和源系统数据是同构的,而且这一层数据粒度是最细的,这层的表分为两种,一种是存储当前需要加载的数据,一种是用于存储处理完后的数据。 - 数据仓库层
它的数据是干净的数据,是一致的、准确的、干净的数据,即对原系统数据进行了清洗后的数据 - 应用层
前端应用直接读取的数据源,根据报表、专题分析需求计算生成的数据
2.Hive
2.1 Hive的基本概念
- 什么是Hive
Hive是基于Hadoop的数据仓库工具,将结构化的数据文件映射为数据库表,并提供类sql的查询语言HQL(Hive Query Language) - Hive的优势和特点
提供了一个简单的优化模型
HQL类SQL语法,简化MR开发
支持在不同的计算框架上运行
支持在HDFS和HBase上临时查询数据
支持用户自定义函数、格式
成熟的JDBC和ODBC驱动程序,用于ETL和BI
稳定可靠(真实生产环境)的批处理
有庞大活跃的社区
2.2 Hive元数据管理
- 记录数据仓库中模型的定义、各层级间的映射关系、监控数据仓库中的数据状态
- 存储在关系数据库中:默认Derby, 轻量级内嵌SQL数据库;实际生产一般存储在MySQL中
- 元数据结构
- 元数据在mysql中的位置
会在MySQL中默认建一个hive库,用来存储元数据
dbs --> 库的信息
tbls --> 表的信息 --> sd_id
sds --> 表存储路径(可以得到数据存储的block块) --> cd_id
cds -->表对应的列及列类型
2.3 hive的命令窗口模式
- 命令行模式:
//直接执行SQL命令
hive -e 'SQL命令'
//执行脚本
hive -f '脚本位置'
- 交互模式:
- Hive命令行(CLI)
hive
命令进入hive - Beeline
方式一:直接进入,不选用用户
开启:nohup hive --service hiveserver2 $
连接:beeline -u jdbc:hive2://localhost:10000
方式二:进入时会选择使用用户
开启:nohup hive --service hiveserver2 $
进入:beeline
连接:!connect jdbc:hive2://hadoop100:10000
- Hive命令行(CLI)
2.4 hive的数据类型
-
原始类型:类似于SQL数据类型
-
复杂数据类型
ARRAY:存储的数据为相同类型
MAP:具有相同类型的键值对
STRUCT:封装了一组字段
create external table employee(
name string,
address array<string>,
genderAndAge struct<gender:string,age:int>,
jobAndSalary map<string,int>,
depAndLvl map<string,string>)
row format delimited
fields terminated by '|'
collection items terminated by ',' //string和struct的分隔符设置
map keys terminated by ':' //map类型的分隔符设置
lines terminated by '\n'
stored as textfile
location '/test/data/emp'
2.5 数据库与数据表
- 数据库
- 表的集合,HDFS中表现为一个文件夹;
默认在hive.metastore.warehouse.dir属性目录下,可以在hive-site.xml修改目录路径;
如果没有指定数据库,默认使用default数据库。 - 库相关的命令
查看库:show databases
查看库的信息:describe database 库名;
建库:create database 库名
使用库:use 库名
查看当前库:select current_database()
删除库:drop database 库名
- 表的集合,HDFS中表现为一个文件夹;
- 数据表
- 内部表(管理表)
HDFS中为所属数据库目录下的子文件夹
数据完全由Hive管理,删除表(元数据)会删除数据 - 外部表(External Tables)
数据保存在指定位置的HDFS路径中
Hive不完全管理数据,删除表(元数据)不会删除数据 - 表相关的命令
建表:create table 表名(column 属性,...)...
删表:drop tables 表名
清空表:truncate 表名
查看表:show tables
- 内部表(管理表)
2.6 建表语句
- 内部表
create table test(id int,name string)
row format delimited
fields terminated by '\t'
- 外部表
create external table test(id int,name string)
row format delimited
fields terminated by '\t'
- 分区表
create external table test(id int,name string)
partitioned by (month string)
row format delimited
fields terminated by '\t'
- 分桶表
create external table test(id int,name string)
clustered by(id) into 3 buckets
row format delimited
fields terminated by '\t'
- 临时表
//表只对当前session有效,退出会话即删除
create temporary table test();
row format delimited
fields terminated by '\t'
- 高级建表语句:
//1、Like
create table test like oldTable; //复制oldTest的表结构来创建test
//2、CTAS – as select方式建表
create table test as select * from test1; //复制test1的数据到test
//3、CTE (CTAS with Common Table Expression)
CREATE TABLE cte_employee AS
WITH
r1 AS (SELECT name FROM r2 WHERE name = 'Michael'),
r2 AS (SELECT name FROM employee WHERE sex_age.sex= 'Male'),
r3 AS (SELECT name FROM employee WHERE sex_age.sex= 'Female')
SELECT * FROM r1 UNION ALL SELECT * FROM r3;
- 完整的建表语句实例:
create external tabkle if not exists employee_external(
name string,
work_place ARRAY<string>,
sex_age STRUCT<sex:string,age:int>,
skills_score MAP<string,int>,
depart_title MAP<STRING,ARRAY<STRING>>)
comment 'This is an external table'
ROW FORMAT DELIMITED
row format delimited
fields treminated by '|'
collection items terminated by ','
map keys terminated by ':',
stored as textfile
- Storage SerDe
SerDe是Serialize/Deserilize的简称,目的是用于序列化和反序列化。
由文件到表 --> 序列化
由表到文件 --> 反序列化
row format serde
"org.apache.hadoop.hive.serde2.OpenCSVSerde"
with serdeproperties(
"separatorChar"=",",
"quoteChar"="\"",
"escapeChar"="\\")
2.7 hive 分区
- 分区主要用于提高性能,分区列的值将表划分为segments(文件夹),查询时使用“分区”列和常规列类似。
创建分区
create external table test(id int,name string)
partitioned by (month string,date string,...)
row format delimited
fields terminated by '\t'
- 静态分区:若分区的值是确定的,那么称为静态分区。新增分区或者是加载分区数据时,已经指定分区名。
添加分区:alter table tab add partition(month='202103') partition(month='202104') ...;
删除分区:alter table tab drop partition(month='202103');
查看表的分区:show partitions tab;
- 动态分区:分区的值是非确定的,由输入数据来确定
- 先设置
允许动态分区:
set hive.exec.dynamic.partition=true;
设置非严格模式:
set hive.exec.dynamic.partition.mode=nostrict;
- 新建中间表tab1,将数据加载进去
- 插入语数据
- 先设置
insert into table tab partition(month)
select id,name,
id as month
from tab1;
2.8 分桶
- 分桶的特点和优点:
分桶对应于HDFS中的文件;
更高的查询处理效率;
使抽样(sampling)更高效;
根据“桶列”的哈希函数将数据进行分桶; - 使用分桶
设置开启分桶功能:set hive.enforce.bucketing = true;
设置reduce的个数:set mapreduce.job.reduces=num;
定义分桶:clustered by (column) into num buckets; //根据列column 分为num个桶
- 分桶抽样 假如分桶数为4
基于整行
select * from tab tablesample(bucket 3 out of 32 on rand()) s;
基于指定列
select * from tab tablesample(bucket 3 out of 32 on id) s;
注:
3表示从第三个分桶开始,32表示取4/32个分桶值,s为别名。即第三个分桶取1/4的数据
2.9 Hive视图(Views)
- 视图概述
通过隐藏子查询、连接和函数来简化查询的逻辑结构
虚拟表,从真实表中选取数据
只保存定义,不存储数据
如果删除或更改基础表,则查询视图将失败
视图是只读的,不能插入或装载数据 - 视图操作
- 创建视图:
create view view_test as select * from tab;
- 查看视图定义:
show create table view_test;
- 查看视图内容:
select * from view_test;
- 删除视图:
drop view ciew_test;
- 创建视图:
- Hive侧视图(Lateral View)
常与表生成函数结合使用,将函数的输入和输出连接
语法实例:
//explode使用:string goods_id='1,2,3,4,5'
//select explode(split(goods_id,',')) as goods_id from explode_lateral_view;
select name,wps,skill,score from employee
lateral view explode(work_place) work_place_single as wps
lateral view explode(skills_score) sks as skill,score;
//explode(数组),如果后面只as一个字段,则表示行转列;如果多个字段,则表示分成多列
2.10 装载数据
- load
给表加载数据
//从本地给表加载数据
load data local inpath '本地文件地址' into table tab1; //原文件不动(复制)
//从HDFS给表加载数据
load data inpath 'HDFS文件地址' into table tab2; //原文件消失(移动)
- insert into
给表加载数据
//INSERT支持OVERWRITE(覆盖)和INTO(追加)
insert into tab1 select * from tab2;
插入多个表:
from ctas_employee
insert into table employee select *
insert overwrite table employee_internal select *;
- insert overwrite
数据导出到文件夹
from tab
insert overwrite local directory '本地文件夹' select *
insert overwrite directory 'hdfs文件夹' select *;
- export 导出数据(表结构,源数据)
export table employee to '/tmp/output3';
- import 导入数据(表结构,源数据)
import table employee from '/tmp/output3';
2.11 Hive数据排序
- ordre by (ASC|DESC)
会对全局做排序,因此只有一个reducer
速度较慢,支持case when或者表达式,支持按位置编号排序 - sort by
不是全局排序,其在数据进入reducer之前完成排序
当Reducer数量设置为1时,等于ORDER BY
排序列必须出现在SELECT column列表中 - distrubute by(字段) 类似于标准SQL中的GROUP BY
根据不同的字段,将数据分到不同的reducer
通常使用在SORT BY语句之前 - cluster by
除了具有distreubute by的功能外,还会对该字段进行排序
2.12 聚合函数
- group by:用于分组
- having:对group by 聚合结果的条件过滤
- 基础的聚合:max, min, count, sum, avg
与GROUP BY一起使用,可应用于列或表达式;
没有GROUP BY则按所有列聚合;
select的列必须包含在GROUP BY中;
对NULL的聚合为0;
2.13 窗口函数
- 概念:
窗口函数是一组特殊函数
扫描多个输入行来计算每个输出值,为每行数据生成一行结果
可以通过窗口函数来实现复杂的计算和聚合 - 语法:
function(arg 1,..., arg n) over([PARTITION BY <...>] [ORDER BY <....>] [<window_clause>])
- 排序
row_number()
:对所有的数值输出不同的序号,序号唯一连续
rank()
:对相同的值,输出相同的序号,下一个序号跳过(1,1,3)
dense_rank()
:对相同的值,输出相同的序号,下一个序号连续(1,1,2)
ntile(n)
:将有序的数据集合平均分配到n个桶中,将桶号分给每一行
percent_rank
:(目前排名/总行数-1),值相当于一组值的百分比排名 - 聚合
max() over():
min() over():
count() over():
sum() over():
avg() over(): - 分析
SELECT
name, dept_num, salary,
LEAD(salary, 2) OVER(PARTITION BY dept_num ORDER BY salary) AS lead,
LAG(salary, 2, 0) OVER(PARTITION BY dept_num ORDER BY salary) AS lag,
FIRST_VALUE(salary) OVER (PARTITION BY dept_num ORDER BY salary) AS first_value,
LAST_VALUE(salary) OVER (PARTITION BY dept_num ORDER BY salary) AS last_value_default,
LAST_VALUE(salary) OVER (PARTITION BY dept_num ORDER BY salary RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_value
FROM employee_contract
ORDER BY dept_num, salary;
- 窗口定义
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
between…and用来指定窗口的起始点和终结点;
Unbounded preceding指明窗口开始于分组的第一行;
Current row作为起始点,指明窗口开始于当前行或当前值;作为终结点,指明窗口结束于当前行或当前值;
Unbounded following指明窗口结束于分组的最后一行;