HSQL
1. 相关概念
1.1 元数据
hive的原始数据是存放在HDFS中,而元数据Metadata(表和文件的映射关系)是存放在MySQL等关系型数据库中
元数据,又称中介数据、中继数据,为描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能
包含用Hive创建的database、table、表的位置、类型、属性,字段顺序类型等元信息
Metastore即元数据服务,作用是管理元数据,对外暴露服务地址,保证了元数据的安全
元数据服务有3种配置方式:内嵌模式、本地模式、远程模式(企业中推荐使用) 元数据和元服务分别存在哪儿?
-
内嵌模式
是默认部署方式,元数据存储在内置的Derby数据库,不需要额外起Metastore服务
但是一次只能支持一个活动用户,适用于测试体验,不适用于生产环境
-
本地模式:把数据库提取出来,元服务在本地
-
远程模式:除了把数据库提取出来,把元服务也提取出来,Metastore全局唯一,减小了性能的下降
1.2 分区
分区是一种优化手段
- 分区是指根据 分区列(例如 “日期day”)的值将表划分为不同分区。这样可以更快地对 指定分区 数据进行查询,避免全表扫描降低性能,前提是保证分区表里面的数据是干净的,不能杂乱,因为hive需要做校验
- 分区在存储上表现为:table表 目录下以子文件夹(分区列=分区值) 形式存在
- Hive还支持分区下继续创建分区,这就是所谓的多重分区
1.3 分桶
分桶是一种优化手段
分桶是指根据表中字段(例如“编号ID”)的 值,经过hash计算规则将数据文件划分为指定的若干个小文件
分桶规则:hashfunc(字段)% 桶个数,余数相同的分到同一个文件
1.4 数据类型
- Hive SQL中,数据类型英文字母大小写不敏感
- 除SQL数据类型外,还支持Java数据类型,比如字符串string
- 复杂数据类型的使用通常需要和分隔符指定语法配合使用
- 如果定义的数据类型和文件不一致,Hive会尝试隐式转换,但是不保证成功
基本类型

集合类型

类型转化
-
转换规则
(1)任何整数类型都可以隐式地转换为一个范围更广的类型,如TINYINT可以转换成INT,INT可以转换成BIGINT
(2)所有整数类型、FLOAT和STRING类型都可以隐式地转换成DOUBLE
(3)TINYINT、SMALLINT、INT都可以转换为FLOAT
(4)BOOLEAN类型不可以转换为任何其它的类型
-
可以使用CAST操作显示进行数据类型转换
例如CAST('1' AS INT) 将把字符串'1' 转换成整数1;如果强制类型转换失败,如执行CAST('X' AS INT),表达式返回空值 NULL。
1.5 SerDe
Hive SerDe,每一张表都会有默认的 SerDe
- SerDe is a short name for "Serializer and Deserializer." (序列化器和反序列化器)
- Hive uses SerDe (and FileFormat) to read and write table rows.
- HDFS files --> InputFileFormat --> <key, value> --> Deserializer --> Row object
- Row object --> Serializer --> <key, value> --> OutputFileFormat --> HDFS files
2. 数据定义语言(DDL)
数据定义语言,是SQL语言集中对数据库内部的对象结构进行创建,删除,修改等的操作语言,这些数据库对象包括database(schema)、table、view、index等
DDL核心语法由CREATE(重点)、ALTER与DROP三个所组成。DDL并不涉及表内部数据的操作
在某些上下文中,该术语也称为数据描述语言,因为它描述了数据库表中的字段和记录
2.1 建表
Hive表默认存储路径是由$ {HIVE_HOME}/ conf/hive-site.xml配置文件的hive.metastore. warehouse.dir属性指定,默认值是:/user/hive/warehouse
建表语句中的语法顺序要和语法树中顺序保持一致
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[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]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
1)创建一个数据库,数据库在HDFS 上的默认存储路径是 /user/hive/warehouse/*.db
hive (default)> create database db_hive;
2)避免要创建的数据库已经存在错误,增加if not exists判断。(标准写法)
hive (default)> create database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Database db_hive already exists
hive (default)> create database if not exists db_hive;
3)创建一个数据库,指定数据库在HDFS上存放的位置
hive (default)> create database db_hive2 location '/db_hive2.db';
SerDe
ROW FORMAT是语法关键字,DELIMITED和SERDE二选其一;
1.如果使用delimited表示使用默认的LazySimpleSerDe类来处理数据
Hive建表时如果没有row format语法指定分隔符,则采用默认分隔符;
默认的分割符是' \001',是一种特殊的字符,使用的是ASCII编码的值,键盘是打不出来的。
示例:创建测试文本
songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,hui long guan_beijing
yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,chao yang_beijing
创建测试表
create table test(
name string,
friends array<string>,
children map<string, int>,
address struct<street:string, city:string>
)
row format delimited fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';
2.如果数据文件格式比较特殊可以使用ROW FORMAT SERDE serde_name指定其他的Serde类来处理数据,甚至支持用户自定义SerDe类,比如读取json文件
内、外部表
内部表
内部表(Internal table)也称为被Hive拥有和管理的托管表(Managed table)
默认情况下创建的表就是内部表,Hive拥有该表的结构和文件。换句话说,Hive完全管理表(元数据和数据)的生命周期,类似于RDBMS中的表
当删除内部表时,它会删除数据以及表的元数据
可以使用DESCRIBE FORMATTED tablename,来获取表的元数据描述信息,从中可以看出表的类型
外部表
外部表(External table )中的数据不是Hive拥有或管理的,只管理表元数据的生命周期
要创建一个外部表,需要使用EXTERNAL语法关键字
删除外部表只会删除元数据,而不会删除实际数据,在Hive外部仍然可以访问实际数据
实际场景中,外部表搭配 location 语法指定数据的路径,可以让数据更安全
分区表
注意∶分区字段不能是表中已经存在的字段,因为分区字段最终也会以虚拟字段的形式显示在表结构上
-
静态分区
所谓静态分区指的是分区的属性值是由用户在加载数据的时候手动指定的
语法如下:
load data [local] inpath 'filepath ' into table tablename partition(分区字段='分区值...);Local参数用于指定待加载的数据是 位于本地文件系统还是HDFS文件系统
本质
- 分区的概念提供了一种将Hive表数据分离为多个文件/目录的方法
- 不同分区对应着不同的文件夹,同一分区的数据存储在同一个文件夹下
- 查询过滤的时候只需要根据分区值找到对应的文件夹,扫描本文件夹下本分区下的文件即可,避免全表数据扫描
- 这种指定分区查询的方式叫做分区裁剪
-
多重分区
常见的是双分区表
通过建表语句中关于分区的相关语法可以发现,Hive支持多个分区字段︰
PARTITIONED BY (partition1 data_type,partition2 data_type,...)多重分区下,分区之间是一种递进关系,可以理解为在前一个分区的基础上继续分区,因此需要注意分区字段的顺序
从HDFS的角度来看就是文件夹下继续划分子文件夹。比如:把全国人口数据首先根据省进行分区,然后根据市进行划分,如果你需要甚至可以继续根据区县再划分,此时就是3分区表
-
动态分区
所谓动态分区指的是分区的字段值是基于查询结果(参数位置)自动推断出来的。核心语法就是insert+select
启用hive动态分区,需要在hive会话中设置两个参数︰
#是否开启动态分区功能 set hive.exec.dynamic.partition=true; #指定动态分区模式,分为nonstick非严格模式(常用)和strict严格模式 #strict严格模式要求至少有一个分区为静态分区 set hive.exec.dynamic.partition.mode=nonstrict;
分区表的注意事项
一、分区表不是建表的必要语法规则,是一种优化手段,可选
二、分区字段不能是表中已有的字段,不能重复
三、分区字段是虚拟字段,其数据并不存储在底层的文件中
四、分区字段值的确定来自于用户价值数据手动指定(静态分区)或者根据查询结果位置自动推断(动态分区)
五、Hive支持多重分区,也就是说在分区的基础上继续分区,划分更加细粒度
分桶表
概念
分桶表也叫做桶表,叫法源自建表语法中bucket单词,是一种用于优化查询而设计的表类型
分桶表对应的数据文件在底层会被分解为若干个部分,通俗来说就是被拆分成若干个独立的小文件
在分桶时,要指定根据哪个字段将数据分为几桶(几个部分)
分桶规则
分桶规则如下︰桶编号相同的数据会被分到同一个桶当中
Bucket number = hash_function(bucketing_column) mod num _buckets
hash_function取决于分桶字段bucketing_column的类型︰
1.如果是int类型,hash_function(int) == int
2.如果是其他比如bigint, string或者复杂数据类型,hash_function比较棘手,将是从该类型派生的某个数字,比如hashcode值
语法
CLUSTERED BY (col_name)表示根据哪个字段进行分
INTO N BUCKETS表示分为几桶(也就是几个部分)
需要注意的是,分桶的字段必须是表中已经存在的字段,通常是id等主键
使用好处
1.基于分桶字段查询时,减少全表扫描
2.JOIN时(JOIN字段是分桶字段)可以提高MR程序效率,减少笛卡尔积数量
3.分桶表数据进行高效抽样
事务表
Hive事务背景知识
-
Hive本身从设计之初时,就是不支持事务的,因为Hive的核心目标是将已经存在的结构化数据文件映射成为表,然后提供基于表的SQL分析处理,是一款面向分析的工具。且映射的数据通常存储于HDFS上,而HDFS是不支持随机修改文件数据的
-
这个定位就意味着在早期的Hive的SQL语法中是没有update, delete操作的,也就没有所谓的事务支持了,因为都是select查询分析操作
-
从Hive0.14版本开始,具有ACID语义的事务已添加到Hive中,以解决以下场景下遇到的问题:
1.流式传输数据
使用如Apache Flume、Apache Kafka之类的工具将数据流式传输到Hadoop集群中。虽然这些工具可以每秒数百行或更多行的速度写入数据,但是Hive只能每隔15分钟到一个小时添加一次分区。如果每分甚至每秒频繁添加分区会很快导致表中大量的分区,并将许多小文件留在目录中,这将给NameNode带来压力
因此通常使用这些工具将数据流式传输到已有分区中,但这有可能会造成脏读(数据传输一半失败,回滚了)。需要通过事务功能,允许用户获得一致的数据视图并避免过多的小文件产生
2.尺寸变化缓慢
星型模式数据仓库中,维度表随时间缓慢变化。例如,零售商将开设新商店,需要将其添加到商店表中,或者现有商店可能会更改其平方英尺或某些其他跟踪的特征。这些更改导致需要插入单个记录或更新单条记录(取决于所选策略)
3.数据重述
有时发现收集的数据不正确,需要更正
局限性
虽然Hive支持了具有ACID语义的事务,但是在使用起来,并没有像在MySQL中使用那样方便,有很多局限性
原因很简单,毕竟Hive的设计目标不是为了支持事务操作,而是支持分析操作,且最终基于HDFS的底层存储机制使得文件的增加删除修改操作需要动一些小心思
一、尚不支持BEGIN,COMMIT和ROLLBACK。所有语言操作都是自动提交的
二、仅支持ORC文件格式(STORED AS ORC )
三、默认情况下事务配置为关闭。需要配置参数开启使用
四、表必须是分桶表( Bucketed )才可以使用事务功能
五、表参数transactional必须为true
六、外部表不能成为ACID表,不允许从非ACID会话读取/写入ACID表
视图
概念
Hive中的视图(view)是一种虚拟表,只保存定义,不实际存储数据
通常从真实的物理表查询中创建生成视图,也可以从已经存在的视图上创建新视图
创建视图时,将冻结视图的架构,如果删除或更改基础表,则视图将失败
视图是用来简化操作的,不缓冲记录,也没有提高查询性能
使用视图的好处
1.将真实表中特定的列数据提供给用户,保护数据隐私,你所看到的都是我想给你看到的
2.降低查询的复杂度,优化查询语句,看上去
物化视图
概念
物化视图(Materialized View)是一个包括查询结果的数据库对像,可以用于预先计算并保存表连接或聚集等耗时较多的操作的结果。在执行查询时,就可以避免进行这些耗时的操作,而从快速的得到结果。
使用物化视图的目的就是通过预计算,提高查询性能,当然需要占用一定的存储空间。
-
Hive3.0开始尝试引入物化视图,并提供对于物化视图的查询自动重写机制(基于Apache Calcite实现)
物化视图创建后即可用于相关查询的加速,即∶用户提交查询query,若该query经过重写后可以命中已经存在的物化视图,则直接通过物化视图查询数据返回结果,以实现查询加速。
是否重写查询使用物化视图可以通过全局参数控制,默认为true : hive.materializedview.rewriting=true;
用户可选择性的控制指定的物化视图查询重写机制,语法如下:
ALTER MATERIALIZED VIEW [db_name.]materialized_view_name ENABLE|DISABLE REWRITE; -
Hive的物化视图还提供了物化视图存储选择机制,可以本地存储在Hive,也可以通过用户自定义storage handlers存储在其他系统(如Druid )
-
Hive引入物化视图的目的就是为了优化数据查询访问的效率,相当于从数据预处理的角度优化数据访问
-
Hive从3.0丢弃了index索引的语法支持,推荐使用物化视图和列式存储文件格式来加快查询的速度
物化视图、视图区别
-
视图是虚拟的,逻辑存在的,只有定义没有存储数据
-
物化视图是真实的,物理存在的,里面存储着预计算的数据
物化视图能够缓存数据,在创建物化视图的时候就把数据缓存起来了,Hive把物化视图当成一张“表”,将数据缓存。而视图只是创建一个虚表,只有表结构,没有数据,实际查询的时候再去改写SQL去访问实际的数据表
-
视图的目的是简化降低查询的复杂度,而物化视图的目的是提高查询性能
2.2 数据库(schema)DDL
show database
1)显示数据库
hive> show databases;
2)过滤显示查询的数据库
hive> show databases like 'db_hive*';
OK
db_hive
db_hive_1
create database
CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path]
[WITH DBPROPERTIES (property_name=property_value, ...)];
describe database
hive> desc database db_hive;
hive> desc database extended db_hive; --显示数据库的详细信息
use database
hive (default)> use db_hive; --切换数据库
drop database
hive>drop database db_hive2; --删除空数据库
hive> drop database if exists db_hive2; --先判断是否存在
hive> drop database db_hive cascade; --强制删除非空数据库,一定要谨慎!!!默认为restrict,无法删除
alter database
更改与Hive中的数据库关联的元数据(数据库属性、数据库拥有者、数据库位置)
2.3 表DDL
Hive中针对表的DDL操作可以说是DDL中的核心操作,包括建表、修改表、删除表、描述表元数据信息
可以说表的定义是否成功直接影响着数据能够成功映射,进而影响是否可以顺利的使用Hive开展数据分析
由于Hive建表之后加载映射数据很快,实际中如果建表有问题,可以不用修改,直接删除重建
describe table
显示Hive中表的元数据信息
如果指定了EXTENDED关键字,则它将以Thrift序列化形式显示表的所有元数据
如果指定了FORMATTED关键字(推荐使用),则它将以表格格式显示元数据
drop table
删除该表的元数据和数据
如果已配置垃圾桶且未指定PURGE,则该表对应的数据实际上将移动到HDFS垃圾桶,而元数据完全丢失
删除EXTERNAL表时,该表中的数据不会从文件系统中删除,只删除元数据
truncate table
从表中删除所有行
可以简单理解为清空表的所有数据但是保留表的元数据结构
如果HDFS启用了垃圾桶,数据将被丢进垃圾桶,否则将被删除
alter table
2.4 分区DDL
Hive中针对分区Partition的操作主要包括:增加分区、删除分区、重命名分区、修复分区、修改分区
add partition
ADD PARTITION会更改表元数据,但不会加载数据。如果分区位置中不存在数据,查询时将不会返回结果
因此 需要保证增加的分区位置路径下,数据已经存在,或者增加完分区之后导入分区数据
rename partition
delete partition
删除表的分区。这将删除该分区的数据和元数据
alter partition
MSCK partition
MSCK partition背景
Hive将每个表的分区列表信息存储在其metastore中。但是,如果将新分区直接添加到HDFS(例如通过使用hadoopfs -put命会)或从HDFS中直接删除分区文件夹,则除非用户ALTER TABLE table_name ADD/DROP PARTITION在每个新添加的分区上运行命令,否则metastore (也就是Hive) 将不会意识到分区信息的这些更改。
MSCK是metastore check的缩写,表示元数据检查操作,可用于元数据的修复
-
MSCK默认行为ADD PARTIONS,使用此选项,它将把HDFS上存在但元存储中不存在的所有分区添加到metastore
-
DROP PARTITIONS选项将从已经从HDFS中删除的metastore中删除分区信息
-
SYNC PARTITIONS选项等效于调用ADD和DROP PARTIFIONS
-
如果存在大量未跟踪的分区,则可以批量运行MSCK REPAIR TABLE,以避免OOME(内存不足错误)
2.5 Show语法
Show相关的语句提供了一种查询Hive metastore的方法。可以帮助用户查询相关信息
比如我们最常使用的查询当前数据库下有哪些表show tables; (显示当前数据库所有表/视图/物化视图/分区/索引)
3. DML
3.1 load
底层会将数据进行复制(本地)、移动(HDFS)
hive> load data [local] inpath '数据的path' [overwrite] into table student [partition (partcol1=val1,…)];
1)LOCAL本地在哪?
如果对HiveServer2服务运行此命令,本地文件系统指的是Hiveserver2服务所在机器的本地Linux文件系统,不是Hive客户端所在的本地文件系统,因为命令会传到Hiveserver2端去执行
2)如果使用了OVERWRITE关键字,则目标表(或者分区)中的已经存在的数据会被删除,然后再将filepath指向的文件/目录中的内容添加到表/分区中
Hive3.0+,load加载数据时除了移动、复制操作之外,在某些场合下还会将加载重写为INSERT AS SELECT
Hive3.0+,还支持使用inputformat、SerDe指定输入格式,例如Text,ORC等
比如,如果表具有分区,则load命令没有指定分区,则将load转换为INSERT AS SELECT,并假定最后一组列为分区列,如果文件不符合预期,则报错。
3.2 insert
假如把Hive当成RDBMS,用insert+values的方式插入数据,会如何?执行过程非常非常慢,原因在于底层是使用MapReduce把数据写入Hive表中
试想一下,如果在Hlive中使用insert+values,对于大数据环境一条条插入数据,用时难以想象。
Hive官方推荐加载数据的方式:清洗数据成为结构化文件,再使用Load语法加载数据到表中。这样的效率更高。
但是并不意味insert语法在Hive中没有用武之地。
Hive中insert的使用方式insert+select,因为ETL过程中常用中间表来保存临时结果,然后利用insert将数据进行保存
insert+select表示:将后面查询返回的结果作为内容插入到指定表中,注意OVERWRITE将覆盖已有数据。
1.需要保证查询结果列的数目和需要插入数据表格的列数目一致
2.如果查询出来的数据类型和插入表格对应的列数据类型不一致,将会进行转换,但是不能保证转换一定成功,转换失败的数据将会为NULL
multiple inserts多重插入
翻译为多次插入,多重插入,其核心功能是︰一次扫描,多次插入
语法目的就是减少扫描的次数,在一次扫描中,完成多次insert操作
动态分区插入
动态分区插入指的是︰分区的值是由后续的select查询语句的结果来动态确定的
根据查询结果自动分区
导出数据
注意:导出操作是一个OVERWRITE覆盖操作,慎重。
事务表
-
Hive的文件是存储在HDFS上的,而HDFS上又不支持对文件的任意修改,只能是采取另外的手段来完成
1)用HDFS文件作为原始数据(基础数据),用delta保存事务操作的记录增量数据;
2)正在执行中的事务,是以一个staging开头的文件夹维护的,执行结束就是delta文件夹。每次执行一次事务操作都会有这样的一个delta增量文件夹;
3)当访问Hive数据时,根据HDFS原始文件和delta增量文件做合并,查询最新的数据。
-
实现原理
INSERT语句会直接创建delta目录;
DELETE目录的前缀是delete_delta;
UPDATE语句采用了split-update特性,即先删除、后插入;
-
实现原理之delta文件夹命名格式
delta_minWID_maxWID_stmtID,即delta前缀、写事务的ID范围、以及语句ID;删除时前缀是delete_delta,里面包含了要删除的文件;
Hive会为写事务(INSERT、DELETE等)创建一个写事务ID (Write ID ),该ID在表范围内唯一;
语句ID (Statement ID)则是当一个事务中有多条写入语句时使用的,用作唯一标识。
-
文件夹下的文件
每个事务的delta文件夹下,都有两个文件︰
_orc_acid_version的内容是2,即当前ACID版本号是2。和版本1的主要区别是UPDATE语句采用了split-update特性,即先删除、后插入。这个文件不是ORC文件,可以下载下来直接查看。
bucket_00000文件则是写入的数据内容。如果事务表没有分区和分桶,就只有一个这样的文件。文件都以ORC格式存储,底层二级制,需要使用ORC TOOLS查看,详见附件资料。
operation:0表示插入,1表示更新,2表示删除。由于使用了split-update,UPDATE是不会出现的,所以delta文件中的operation是0 , delete_delta文件中 的operation是2。
originalTransaction、currentTransaction:该条记录的原始写事务ID,当前的写事务ID。
rowld:一个自增的唯一ID,在写事务和分桶的组合中唯一。
row:具体数据。对于DELETE语句,则为null,对于INSERT就是插入的数据,对于UPDATE就是更新后的数据。
-
合并器
随着表的修改操作,创建了越来越多的delta增量文件,就需要合并以保持足够的性能。
合并器Compactor是一套在Hlive Metastore内运行,支持ACID系统的后台进程。所有合并都是在后台完成的,不会阻止数据的并发读、写。合并后,系统将等待所有旧文件的读操作完成后,删除旧文件。
合并操作分为两种,minor compaction (小合并)、major compaction (大合并):
小合并会将一组delta增量文件重写为单个增量文件,默认触发条件为10个delta文件;
大合并将一个或多个增量文件和基础文件重写为新的基础文件,默认触发条件为delta文件相应于基础文件占比,10%。 -
局限性
虽然Hive支持了具有ACID语义的事务,但是在使用起来,并没有像在MySQL中使用那样方便,有很多限制;
1.尚不支持BEGIN,COMMIT和ROLLBACK,所有语言操作都是自动提交的;
2.表文件存储格式仅支持ORC ( STORED AS ORC);
3.需要配置参数开启事务使用;
4.外部表无法创建为事务表,因为Hive只能控制元数据,无法管理数据;
5.表属性参数transactional必须设置为true;
6.必须将Hive事务管理器设置为org. apache. hadoop.hive.ql.lockmgr. DbTxnManager才能使用ACID表;
7.事务表不支持LOAD DATA ...语句。
4. DQL
select
从哪里查询取决于FROM关键字后面的table_reference。可以是普通物理表、视图、join结果或子查询结果
表名和列名不区分大小写
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]
where不可以与聚合函数一起使用,因为并不确定会有多少条数据进行聚合;所以group by提供了having来对数据进行筛选
为了避免歧义,出现在GROUP BY中select_expr的字段∶要么是GROUP BY分组的字段;要么是被聚合函数应用的字段。
执行顺序
在查询过程中执行顺序:from > where > group(含聚合) > having > order > select
1.聚合语句(sum, min, max, avg, count) 要比 having 子句优先执行
2.where子句在查询过程中执行优先级别优先于聚合语句(sum, min, max, avg, count)
结合下面SQL感受:
select state,sum(deaths) as cnts
from t_usa_covid19_p
where count_date="2021-01-28"
group by state
having cnts>10000;
4.1 ORDER BY
-
Hive SQL中的ORDER BY语法类似于标准SQL语言中的ORDER BY语法,会对输出的结果进行全局排序
因此当底层使用MapReduce引擎执行的时候,只会有一个reducetask执行。如果输出的行数太大,会导致需要很长的时间才能完成全局排序。如果说没有特别需求尽量少使用
-
默认排序为升序(ASC) ,也可以指定为DESC降序
-
在Hive 2.1.0和更高版本中,支持在ORDER BY子句中为每个列指定null类型结果排序顺序
ASC顺序的默认空排序顺序为NULLS FIRST,而DESC顺序的默认空排序顺序为NULLS LAST
4.2 CLUSTER BY
根据指定字段将数据分组,每组内再根据该字段正序排序(只能正序)
概况起来就是∶根据同一个字段,分且排序。
1.分组规则hash散列(分桶表规则一样) :Hash_Func(col_name)% reducetask个数
2.分为几组取决于reducetask的个数
4.3 DISTRIBUTE BY +SORT BY
DISTRIBUTE Bl +SORT BY就相当于把 CLUSTER BY 的功能一分为二︰
- DISTRIBUTE BY负责根据指定字段分组;
- SORT BY负责分组内排序规则。
分组和排序的字段可以不同。
CLUSTER、DISTRIBUTE、SORT、ORDER BY
- order by全局排序,因此只有一个reducer,结果输出在一个文件中,当输入规模大时,需要较长的计算时间。
- distribute by根据指定字段将数据分组,算法是hash散列。sort by是在分组之后,每个组内局部排序。
- cluster by既有分组,又有排序,但是两个字段只能是同一个字段。
如果distribute和sort的字段是同一个时,此时,cluster by = distribute by + sort by
4.4 Union
UNION用于将来自于多个SELECT语句的结果合并为一个结果集
1.使用DISTINCT关键字与只使用UNION默认值效果一样,都会删除重复行。1.2.0之前的Hive版本仅支持UNIONALL,在这种情况下不
会消除重复的行。
2.使用ALL关键字,不会删除重复行,结果集包括所有SELECT语句的匹配行(包括重复行)。
3.每个select_statement返回的列的数量和名称必须相同。
4.5 CTE
公用表表达式(CTE )是一个临时结果集:该结果集是从WITH子句中指定的简单查询派生而来的,紧接在SELECT或INSERT关键字之前
CTE仅在单个语句的执行范围内定义
CTE可以在SELECT,INSERT,CREATE TABLE AS SELECT或CREATE VIEW AS SELECT语句中使用
4.6 JOIN
inner join(内连接)、left join(左连接)、right join (右连接)、full outer join (全外连接)、left semi join (左半开连接)、cross join(交叉连接,也叫做笛卡尔乘积)
inner join
内连接是最常见的一种连接,它也被称为普通连接,其中inner可以省略:inner join == join ;
只有进行连接的两个表中都存在与连接条件相匹配的数据才会被留下来,相当于求交集
left join
left join中文叫做是左外连接(Left Outer Join)或者左连接,其中outer可以省略,left outer join是早期的写法
left join的核心就在于left左。左指的是join关键字左边的表,简称左表
通俗解释:join时以左表的全部数据为准,右边与之关联;左表数据全部返回,右表关联上的显示返回,关联不上的显示null返回,相当于左外加上交集
right join
和left join相似,只是方向反了,相当于 右外加上交集
full outer join
返回所有满足条件的行
left semi join
相当于 inner join 后返回只左表的数据
cross join
交叉连接cross join,将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积。对于大表来说,cross join慎用
cross join后再跟一个where或on进行过滤
注意事项
a) 允许使用复杂的联接表达式,支持非等值连接
b) 同一查询中可以连接2个以上的表
c) 如果每个表在联接子句中使用相同的到,则Hive将多个表上的联接转换为单个MR作业
d) join时的最后一个表会通过reducer流式传输,并在其中缓冲之前的其他表,因此,将大表放置在最后有助于减少reducer阶段缓存数据所需要的内存
e) 在join的时候,可以通过语法STREAMTABLE提示指定要流式传输的表。如果省略STREAMTABLE提示,则Hive将流式传输最右边的表
f) join在WHERE条件之前进行
g) 如果除一个要连接的表之外的所有表都很小,则可以将其作为仅map作业执行(mapjoin)
5. Hive Functions
内置函数
数值类型函数、日期类型函数、字符串类型函数、集合函数、条件函数等
explode
-
explode接收map、array类型的数据作为输入,然后把输入数据中的每个元素拆开变成一行数据,一个元素一行
-
explode执行效果正好满足于输入一行输出多行,叫做UDTF函数
-
一般情况下,explode函数可以直接单独使用即可
-
也可以根据业务需要结合lateral view侧视图一起使用
explode(array) 将array里的每个元素生成一行
explode(map) 将map里的每一对元素作为一行,其中key为一列,value为一列
UDTF语法限制
- explode函数属于UDTF表生成函数,explode执行返回的结果可以理解为一张虚拟的表,其数据来源于源表
- 在select中只查询源表数据没有问题,只查询explode生成的虚拟表数据也没问题,但是不能在只查询源表的时候,既想返回源表字段又想返回explode生成的虚拟表字段;通俗点讲,有两张表,不能只查询一张表 但是又想返回分别属于两张表的字段
UDTF语法限制解决
-
从SQL层面上来说上述问题的解决方案是:对两张表进行join关联查询
-
Hive专门提供了语法lateral View侧视图,专门用于搭配explode这样的UDTF函数,以满足上述需要
lateral View侧视图
将UDT的结果构建成一个类似于视图的表,然后将原表中的每一行和UDTF函数输出的每一行进行连接,生成—张新的虚拟表。这样就避免了UDTF的使用限制问题
使用lateral view时也可以对UDTF产生的记录设置字段名称,产生的字段可以用于group by、order by、limit等语句中,不需要再单独嵌套一层子查询
用户定义函数UDF
UDF(一进一出)、UDAF(多进一出)、UDTF(一进多出)
常用函数
空字段赋值
NVL( value,default_value)
如果value为NULL,则NVL函数返回default_value的值,否则返回value的值,如果两个参数都为NULL ,则返回NULL
CASE WHEN THEN ELSE END
select
dept_id,
sum(case sex when '男' then 1 else 0 end) male_count,
sum(case sex when '女' then 1 else 0 end) female_count
from
emp_sex
group by
dept_id;
行列转换
多行转多列:先进行分组 然后使用case when函数进行匹配
多行转单列:先进行分组 然后使用collect_list函数进行收集(注 收集的时候将类型转换为string) 最后使用concat_ws函数(可以指定分割符,只支持string或array<string>)进行连接
多列转多行:使用union all 关键字
单列转多行:使用explode函数(只支持Map或Array)+ 侧视图
窗口函数
概述
窗口函数(Window functions )也叫做开窗函数、OLAP函数,其最大特点是∶输入值是从 SELECT 语句的结果集中的一行或多行的“窗口”中获取的
如果函数具有 OVER 子句,则它是窗口函数
与GROUP BY的区别:窗口函数可以简单地解释为类似于聚合函数的计算函数,但是通过GROUP BY子句组合的常规聚合会隐藏正在聚合的各个行,最终输出一行,窗口函数聚合后还可以访问当中的各个行,并且可以将这些行中的某些属性添加到结果集中
窗口表达式
在sum(...) over( partition by... order by ...)语法完整的情况下,进行累积聚合操作,默认累积聚合行为是:从第一行聚合到当前行
Window expression窗口表达式给我们提供了一种控制行范围的能力,比如向前2行,向后3行。
语法如下:
关键字是rows between,包括下面这几个选项
- preceding :往前
- following :往后
- current row :当前行
- unbounded :边界
- unbounded preceding :表示从前面的起点
- unbounded following :表示到后面的终点
窗口排序函数 - row_number家族
row _number:在每个分组中,为每行分配一个从1开始的唯一序列号,递增,不考虑重复
rank:在每个分组中,为每行分配一个从1开始的序列号,考虑重复,挤占后续位置
dense_rank:在每个分组中,为每行分配一个从1开始的序列号,考虑重复,不挤占后续位置
窗口排序函数 - ntil
将每个分组内的数据分为指定的若干个桶里(分为若干个部分),并且为每一个桶分配一个桶编号
如果不能平均分配,则优先分配较小编号的桶,并且各个桶中能放的行数最多相差1
有时会有这样的需求:如果数据排序后分为三部分,业务人员只关心其中的一部分,如何将这中间的三分之一数据拿出来?
窗口分析函数
-
LAG(col, n, DEFAULT) 用于统计窗口内往上第n行值
第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL ) ;
-
LEAD(col, n, DEFAULT) 用于统计窗口内往下第n行值
第一个参数为列名,第二个参数为往下第n行(可选,默认为1),第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL ) ;
-
FIRST_VALUE 取分组内排序后,截止到当前行,第一个值
-
LAST_VALUE 取分组内排序后,截止到当前行,最后一个值
抽样函数
概述
当数据量过大时,我们可能需要查找数据子集以加快数据处理速度分析
这就是抽样、采样,一种用于识别和分析数据中的子集的技术,以发现整个数据集中的模式和趋势
在HQL中,可以通过三种方式采样数据∶随机采样,存储桶表采样和块采样
-
Random随机抽样
- 随机抽样使用 rand() 函数来确保随机获取数据,LIMIT来限制抽取的数据个数
- 优点是随机,缺点是速度不快,尤其表数据多的时候
1)推荐DISTRIBUTE+SORT,可以确保数据也随机分布在 mapper和reducer 之间,使得底层执行有效率
2)ORDER BY语句也可以达到相同的目的,但是表现不好,因为ORDER BY是全局排序,只会启动运行一个reducer
-
Block基于数据块抽样
- Block块采样允许随机获取n行数据、百分比数据或指定大小的数据
- 采样粒度是HDFS块大小
- 优点是速度快,缺点是不随机
-
Bucket table基于分桶表抽样
-
这是一种特殊的采样方法,针对分桶表进行了优化。优点是既随机 速度也很快
-
语法如下:
TABLESAMPLE (BUCKET x oUT oF y [oN colname]) --1、y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。 --例如,table总共分了4份(4个bucket),当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据。 --2、x表示从哪个bucket开始抽取。 --例如,table总bucket数为4,tablesample(bucket 4 out of 4)表示总共抽取(4/4=)1个bucket的数据,抽取第4个bucket的数据。 --注意:x的值必须小于等于y的值,否则FAILED:Numerator should not be bigger than denorninator in sample clause for table stu_buck --3、ON colname表示基于什么抽 --ON rand()表示随机抽 --ON 分桶字段 表示基于分桶字段抽样 效率更高 推荐
-
JSON数据处理
get_json_object
用于解析JSON字符串,可以从JSON字符串中返回指定的某个对象列的值
参数
第一个参数:指定要解析的JSON字符串
第二个参数:指定要返回的字段,通过$.columnName的方式来指定path
特点:每次只能返回JSON对象中一列的值
--语法
get_json_object(json_txt, path) - Extract a json object from path
--切换数据库
use db_function;
--创建表
create table tb_json_test1 (
json string
);
--加载数据
load data local inpath '/export/data/device.json' into table tb_json_test1;
--获取设备名称字段
select
json,
get_json_object(json,"$.device") as device
from tb_json_test1;
json_tuple
用于实现JSON字符串的解析,可以通过指定多个参数来解析JSON返回多列的值
--语法
json_tuple(jsonStr, p1, p2, ..., pn)
like get_json_object, but it takes multiple names and return a tuple
--返回设备名称及信号强度
select
json_tuple(json,"device","signal") as (device,signal)
from tb_json_test1;
JSONSerde
上述解析JSON的过程中是将数据 作为一个JSON字符串 加载到表中,再通过JSON解析函数对JSON字符串进行解析,灵活性比较高
但是对于如果整个文件就是一个JSON文件,在使用起来就相对比较麻烦
Hive中为了简化对于JSON文件的处理,内置了一种专门用于解析JSON文件的Serde解析器,在创建表时,只要指定使用JSONSerde解析表的文件,就会自动将JSON文件中的每一列进行解析
--切换数据库
use db_function;
--创建表
create table tb_json_test2 (
device string,
deviceType string,
signal double,
`time` string
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
load data local inpath '/export/data/device.json' into table tb_json_test2;
select * from tb_json_test2;
小结
不论是Hive中的JSON函数还是自带的JSONSerde,都可以实现对于JSON数据的解析,工作中一般根据数据格式以及对应的需求来实现解析
如果数据中每一行只有个别字段是JSON格式字符串,就可以使用JSON函数来实现处理
但是如果数据加载的文件整体就是JSON文件,每一行数据就是一个JSON数据,那么建议直接使用JSONSerde来实现处理最为方便
6. 性能调优
6.1 表设计优化
分区表
Hive查询基本原理
-
Hive的设计思想是通过元数据解析描述将 HDFS上的文件 映射成表
-
基本的查询原理是当用户通过HQL语句对Hive中的表进行复杂数据处理和计算时,默认将其转换为分布式计算MapReduce程序对HDFS中的数据进行读取处理的过程
-
当执行查询计划时,Hive会使用表的 最后一级目录 作为底层处理数据的输入
采用分区避免了全表扫描,最后一级目录为分区目录,只需要扫描指定分区目录即可,分区字段必须是查询字段
分桶表
Hive中Join的问题
- 默认情况下,Hive底层是通过MapReduce来实现的
- MapReduce在处理数据之间join的时候有两种方式:MapJoin、ReduceJoin,其中MapJoin效率较高
- 如果有两张非常大的表要进行Join,底层无法使用MapJoin提高Join的性能,只能走默认的ReduceJoin
- 而ReduceJoin必须经过Shuffle过程,相对性能比较差,而且容易产生数据倾斜
分桶表设计思想
- 分区表是将数据划分不同的目录进行存储,而分桶表是将数据划分不同的文件进行存储
- 分桶表的设计是按照一定的规则【底层通过MapReduce中的多个Reduce来实现】将数据划分到不同的文件中进行存储,构建分桶表
- 如果有两张表按照相同的划分规则【比如按照Join的关联字段】将各自的数据进行划分
- 在Join时,就可以实现Bucket与Bucket的Join,避免不必要的比较,减少笛卡尔积数量
开启SMB(Sort-Merge-Buket) Join,既分桶又排序 提高Join性能,采用分桶避免了全表之间的Join,而是桶之间的Join,分桶字段必须是Join字段,桶的数目相同或成倍数
Hive索引
注:Hive3.0以后不再支持索引
索引存在的问题
- Hive构建索引的过程是通过一个MapReduce程序来实现的;
- 每次Hive中原始数据表的数据发生更新时,索引表不会自动更新;
- 必须手动执行一个Alter index命令来实现通过MapReduce更新索引表,导致整体性能较差,维护相对繁琐
由于Hive的索引设计过于繁琐,所以从Hive3.0版本开始,取消了对Hive Index的支持及使用
如果使用的是Hive1.x或者Hive2.x,在特定的场景下依旧可以使用Hive Index来提高性能
实际工作场景中,一般不推荐使用Hive Index,推荐使用ORC文件格式中的索引、物化视图来代替Hive Index提高查询性能
6.2 表数据优化
文件格式
Hive数据存储的本质还是HDFS,所有的数据读写都基于HDFS的文件来实现
为了提高对HDPS文件读写的性能,Hive提供了多种文件存储格式:TextFile、SequenceFile、ORC、Parquet等
不同的文件存储格式具有不同的存储特点,有的可以降低存储空间,有的可以提高查询性能
TextFile
TextFile是Hive中默认的文件格式,存储形式为按行存储
工作中最常见的数据文件格式就是TextFile文件,几乎所有的原始数据生成都是TextFile格式,所以Hive设计时考虑到为了避免各种编码及数据错乱的问题,选用了TextFile作为默认的格式
建表时不指定存储格式即为TextFile,导入数据时把数据文件拷贝至HDFS不进行处理
SequenceFile
SequenceFile是Hadoop里用来存储序列化的键值对 即二进制的一种文件格式
SequenceFile文件也可以作为MapReduce作业的输入和输出,hive也支持这种格式
优点:以二进制的KV形式存储数据;与底层交互更加友好,性能更快;可压缩、可分割,优化磁盘利用率和I/O;可并行操作数据,查询效率高;也可以用于存储多个小文件
缺点:存储空间消耗最大;与非Hadoop生态系统之外的工具不兼容;构建SequenceFile需要通过TextFile文件转化加载
应用场景:适合于小量数据,但是查询列比较多的场景
支持不同级别的压缩,按一条记录进行压缩或者多条记录按块进行压缩
使用insert+select MR源码程序导入数据
Parquet
Parquet是一种支持嵌套结构的列式存储文件格式,最早是由Twitter和Cloudera合作开发,2015年5月从Apache孵化器里毕业成为Apache顶级项目
是一种支持嵌套数据模型对的列式存储系统,作为大数据系统中OLAP查询的优化方案,它已经被多种查询引擎原生支持,并且部分高性能引擎将其作为默认的文件存储格式
通过数据编码和压缩,以及映射下推和谓词下推功能,Parquet的性能也较之其它文件格式 有所提升
优点:更高效的压缩和编码可压缩、可分割,优化磁盘利用率和I/O;可用于多种数据处理框架
缺点:不支持update, insert, delete, ACID
应用场景:适用于字段数非常多,无更新,只取部分列的查询
ORC
推荐使用!
ORC(OptimizedRC File)文件格式也是一种Hadoop生态圈中的列式存储格式;
它的产生早在2013年初,最初产生自Apache Hive,用于降低Hadoop数据存储空间和加速Hive查询速度;
2015年ORC项目被Apache项目基金会提升为Apache顶级项目。
优点:列式存储,存储效率非常高;可压缩,高效的列存取;查询效率较高,支持索引;支持矢量化查询
缺点:加载时性能消耗较大;需要通过text文件转化生成;读取全量数据时性能较差
应用场景:适用于Hive中大型的存储、查询
lORC不是一个单纯的列式存储格式,仍然是首先根据行组分割整个表,在每一个行组内进行按列存储。
lORC文件是自描述的,它的元数据使用Protocol Buffers序列化,并且文件中的数据尽可能的压缩以降低存储空间的消耗,目前也被Hive、Spark SQL、Presto等查询引擎支持。
数据压缩
Hive底层运行MapReduce程序时,磁盘I/O操作、网络数据传输、shuffle和merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下。
鉴于磁盘I/O和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源、最小化磁盘I/O和网络传输非常有帮助。
Hive压缩实际上说的就是MapReduce的压缩。
压缩的优点
减小文件存储所占空间
加快文件传输效率,从而提高系统的处理速度
降低IO读写的次数
压缩的缺点
使用数据时需要先对文件解压,加重CPU负荷,压缩算法越复杂,解压时间越长
不用的压缩算法配合不同的文件存储格式 可以带来更好的效果!
存储优化
避免小文件生成
Hive的存储本质还是HDFS,HDFS是不利于小文件存储的,因为每个小文件会产生一条元数据信息,并且不利用MapReduce的处理,MapReduce中每个小文件会启动一个MapTask计算处理,导致资源的浪费,所以在使用Hive进行处理分析时,要尽量避免小文件的生成。
Hive中提供了一个特殊的机制,可以自动的判断是否是小文件,如果是小文件可以自动将小文件进行合并。
合并小文件
如果遇到数据处理的输入是小文件的情况,怎么解决呢?
Hive中也提供一种输入类CombineHiveInputFormat,用于将小文件合并以后,再进行处理。
ORC文件索引
在使用ORC文件时,为了加快读取ORC文件中的数据内容,ORC提供了两种索引机制:Row Group Index 和 Bloom Filter Index可以帮助提高查询ORC文件的性能
当用户写入数据时,可以指定构建索引,当用户查询数据时,可以根据索引提前对数据进行过滤,避免不必要的数据扫描。
Row Group Index
一个ORC文件包含一个或多个stripes(groups of row data),每个stripe中包含了每个column的min/max值的索引数据;
当查询中有大于等于小于的操作时,会根据min/max值,跳过扫描不包含的stripes。
而其中为每个stripe建立的包含min/max值的索引,就称为Row Group Index行组索引,也叫min-max Index大小对比索引,或者Storage Index。
建立ORC格式表时,指定表参数’orc.create.index’=’true’之后,便会建立Row Group Index;
为了使Row Group Index有效利用,向表中加载数据时,必须对需要使用索引的字段进行排序
Bloom Filter Index
建表时候通过表参数”orc.bloom.filter.columns”=”columnName……”来指定为哪些字段建立BloomFilter索引,在生成数据的时候,会在每个stripe中,为该字段建立BloomFilter的数据结构;
当查询条件中包含对该字段的等值过滤时候,先从BloomFilter中获取以下是否包含该值,如果不包含,则跳过该stripe。
ORC矢量化查询
Hive的默认查询执行引擎一次处理一行,而矢量化查询执行是一种Hive针对ORC文件操作的特性,目的是按照每批1024行读取数据,并且一次性对整个记录整合(而不是对单条记录)应用操作,提升了像过滤, 联合, 聚合等等操作的性能。
注意:要使用矢量化查询执行,就必须以ORC格式存储数据。
6.3 Job作业执行优化
Explain查询计划
HiveQL是一种类SQL的语言,从编程语言规范来说是一种声明式语言,用户会根据查询需求提交声明式的HQL查询,而Hive会根据底层计算引擎将其转化成Mapreduce/Tez/Spark的job;
explain命令可以帮助用户了解一条HQL语句在底层的实现过程。通俗来说就是Hive打算如何去做这件事。
explain会解析HQL语句,将整个HQL语句的实现步骤、依赖关系、实现过程都会进行解析返回,可以了解一条HQL语句在底层是如何实现数据的查询及处理的过程,辅助用户对Hive进行优化。
官网:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Explain
每个查询计划由以下几个部分组成:
抽象语法树(AST):Hive使用Antlr解析生成器,可以自动地将HQL生成为抽象语法树
Stage依赖关系:会列出运行查询划分的stage阶段以及之间的依赖关系
Stage内容:包含了每个stage非常重要的信息,比如运行时的operator和sort orders等具体的信息
MapReduce属性优化
本地模式
1.使用Hive的过程中,有一些数据量不大的表也会转换为MapReduce处理,提交到集群时,需要申请资源,等待资源分配,启动JVM进程,再运行Task,一系列的过程比较繁琐,本身数据量并不大,提交到YARN运行返回会导致性能较差的问题。
2.Hive为了解决这个问题,延用了MapReduce中的设计,提供本地计算模式,允许程序不提交给YARN,直接在本地运行,以便于提高小数据量程序的性能。
JVM重用
1.Hadoop默认会为每个Task启动一个JVM来运行,而在JVM启动时内存开销大;
2.Job数据量大的情况,如果单个Task数据量比较小,也会申请JVM,这就导致了资源紧张及浪费的情况;
3.JVM重用可以使得JVM实例在同一个job中重新使用N次,当一个Task运行结束以后,JVM不会进行释放,而是继续供下一个Task运行,直到运行了N个Task以后,就会释放;
4.N的值可以在Hadoop的mapred-site.xml文件中进行配置,通常在10-20之间。
-- Hadoop3之前的配置,在mapred-site.xml中添加以下参数
-- Hadoop3中已不再支持该选项
mapreduce.job.jvm.numtasks=10
并行执行
1.Hive在实现HQL计算运行时,会解析为多个Stage,有时候Stage彼此之间有依赖关系,只能挨个执行,但是在一些别的场景下,很多的Stage之间是没有依赖关系的;
2.例如Union语句,Join语句等等,这些Stage没有依赖关系,但是Hive依旧默认挨个执行每个Stage,这样会导致性能非常差,我们可以通过修改参数,开启并行执行,当多个Stage之间没有依赖关系时,允许多个Stage并行执行,提高性能。
Join优化
1.Map Join
2.Reduce Join
3.Bucket Join
优化器
关联优化
当一个程序中如果有一些操作彼此之间有关联性,是可以在一个MapReduce中实现的,但是Hive会不智能的选择,Hive会使用两个MapReduce来完成这两个操作。
优化器引擎
基于规则的优化器 RBO(rule basic optimise),默认引擎
基于代价的优化器 CBO(cost basic optimise)
谓词下推(PPD)
不影响最终结果的情况下,尽量将过滤条件提前执行,默认开启
数据倾斜
数据倾斜 - Group by、Count(distinct)
方案一:开启Map端聚合
方案二:实现随机分区
方案三:数据倾斜时自动负载均衡
数据倾斜 - Join
方案一:提前过滤,将大数据变成小数据,实现Map Join
方案二:使用Bucket Join
方案三:使用Skew Join

浙公网安备 33010602011771号