hive 知识点总结

官方手册

Hive基本概念

什么是hive

是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
将HQL转化成Map Reduce程序
Hive处理的数据存储在HDFS
Hive分析数据底层的实现是Map Reduce
执行程序运行在Yarn上

Hive架构的组成部分

在这里插入图片描述

  • 客户端(Client)

    • 访问 Hive
  • 元数据(Meta Store)

    • 元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;

    • 默认存储在自带的derby数据库中,推荐使用MySQL存储Meta Store

      不选择Derby数据库来存储元数据的原因:

      1. Derby数据库,只能允许一个会话连接,不支持并发,当一个用户在Hive进行操作时,其他用户则无法操作
      2. Derby还有一个特性。更换目录执行操作,会找不到相关表等;比如在/usr下执行创建表,在/usr下可以找到这个表。在/etc下执行查找这个表,就会找不到 。
  • Hadoop

    • 使用HDFS进行存储,使用Map Reduce进行计算。
  • 驱动器

    • 解析器(SQL Parser)
      • 将SQL字符串转换成抽象语法树AST,对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误
    • 编译器(Physical Plan)
      • 将抽象语法树进行编译生成逻辑执行计划。
    • 优化器(Query Optimizer)
      • 对逻辑执行计划进行优化。
    • 执行器(Execution)
      • 把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark。

在这里插入图片描述

Hive通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(Meta Store),将这些指令翻译成Map Reduce,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口。

hive 架构(官方截取)

官方参考地址
在这里插入图片描述

Hive的优缺点

  • 优点
    • 操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。
    • 避免了去写Map Reduce,减少开发人员的学习成本。
    • Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合。
    • Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执行延迟比较高。
    • Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
  • 缺点
    • Hive的HQL表达能力有限
      • 迭代式算法无法表达
      • 数据挖掘方面不擅长,由于Map Reduce数据处理流程的限制,效率更高的算法却无法实现。
    • Hive的效率比较低
      • Hive自动生成的Map Reduce作业,通常情况下不够智能化
      • Hive调优比较困难,粒度较粗

数据类型

基本数据类型

Hive 数据类型Java 数据类型长度例子
TINYINTbyte1byte 有符号整数20
SMALINTshort2byte 有符号整数20
INTint4byte 有符号整数20
BIGINTlong8byte 有符号整数20
BOOLEANboolean

布尔类型,true 或者

false

TRUE FALSE
FLOATfloat单精度浮点数3.14159
DOUBLEdouble双精度浮点数3.14159
STRINGstring字符系列。可以指定字符集。可以使用单引号或者双引号。

‘ now is the time ’

“for all good men”

TIMESTAMP时间类型
BINARY字节数组

对于 Hive 的 String 类型相当于数据库的 varchar 类型,该类型是一个可变的字符串,不过它不能声明其中最多能存储多少个字符,理论上它可以存储 2GB 的字符数。

集合数据类型

数据类型描述语法示例
STRUCT

和 c 语言中的 struct 类似,都可以通过“点”符号访

问元素内容。例如,如果某个列的数据类型是 STRUCT{first STRING, last STRING},那么第 1 个元素可以通过字段.first 来引用。

struct()

例 如 struct<street:string,

city:string>

MAPMAP 是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是 MAP,其中键 ->值对是’first’->’John’和’last’->’Doe’,那么可以通过字段名[‘last’]获取最后一个元素map() 例如 map<string, int>
ARRAY数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为[‘John’, ‘Doe’],那么第 2 个元素可以通过数组名[1]进行引用。

Array()

例如 array

Hive 有三种复杂数据类型 ARRAY、MAP 和 STRUCT。ARRAY 和 MAP 与 Java 中的 Array 和 Map 类似,而 STRUCT 与 C 语言中的 Struct 类似,它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套。

DDL 数据定义

创建数据库

CREATE [REMOTE] (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
  [COMMENT database_comment]
  [LOCATION hdfs_path]
  [MANAGEDLOCATION hdfs_path]
  [WITH DBPROPERTIES (property_name=property_value, ...)];

字段说明:

  • SCHEMA 和 DATABASE 的用途是可以互换的——它们的意思是一样的
  • IF NOT EXISTS : 如果不存在
  • COMMENT : 数据库的描述信息
  • LOCATION :指定数库的存放位置
  • MANAGEDLOCATION : LOCATION 现在指的是外部表的默认目录,而 MANAGEDLOCATION 指的是托管表的默认目录。建议将 MANAGEDLOCATION 放在 metastore.warehouse.dir 中,这样所有托管表都有一个共同的根目录,其中包含共同的治理策略。它可以与 metastore.warehouse.tenant.colocation 一起使用,使其指向仓库根目录之外的目录,从而拥有基于租户的公共根目录,可以在其中设置配额和其他策略。

查询数据库

显示数据库

show databases[like 'db_name'];

说明:

  • like : 过滤显示查询的数据库

查看数据库详情

显示数据库信息【desc】
desc database db_name
显示数据库详细信息【extended】
desc database extended db_name;

修改数据库

ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...);   -- (Note: SCHEMA added in Hive 0.14.0)
 
ALTER (DATABASE|SCHEMA) database_name SET OWNER [USER|ROLE] user_or_role;   -- (Note: Hive 0.13.0 and later; SCHEMA added in Hive 0.14.0)
  
ALTER (DATABASE|SCHEMA) database_name SET LOCATION hdfs_path; -- (Note: Hive 2.2.1, 2.4.0 and later)
 
ALTER (DATABASE|SCHEMA) database_name SET MANAGEDLOCATION hdfs_path; -- (Note: Hive 4.0.0 and later)

说明:

  • SCHEMA 和 DATABASE 的用途是可以互换的——它们的意思是一样的。
  • ALTER DATABASE … SET LOCATION 语句不会将数据库当前目录的内容移动到新指定的位置。它不会更改与指定数据库下的任何表/分区关联的位置。它仅更改将为该数据库添加新表的默认父目录。这种行为类似于更改表目录不会将现有分区移动到其他位置。
  • ALTER DATABASE … SET MANAGEDLOCATION 语句不会将数据库托管表目录的内容移动到新指定的位置。它不会更改与指定数据库下的任何表/分区关联的位置。它仅更改将为该数据库添加新表的默认父目录。这种行为类似于更改表目录不会将现有分区移动到其他位置。
  • 不能更改有关数据库的其他元数据。

删除数据库

DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE];

字段说明:

  • SCHEMA 和 DATABASE 的用途是可以互换的——它们的意思是一样的。
  • IF NOT EXISTS : 如果不存在

创建表

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 ]

说明:

  • CREATE TABLE : 创建一个指定名字的表,如果相同名字的表已经存在,则抛出异常。可以使用 IF NOT EXISTS 选项来忽略这个异常。
  • EXTERNAL : 可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION).Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据.
  • LIKE: 允许用户复制现有的表结构,但是不复制数据。
  • ROW FORMAT DELIMITED : 是用来设置创建的表在加载数据的时候,支持的列分隔符。Hive默认的分隔符是\001,属于不可见字符,这个字符在vi里是^A
  • STORED AS :SEQUENCEFILE|TEXTFILE|RCFILE,如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
  • CLUSTERED BY : 对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
  • LOCATION : 指定加载数据路径(指定在hdfs上的位置).针对的extetnal外部表,要指定存储路径,不指定也没事,默认路径。内部表不用指定,默认路径/user/hive/warehouse。CREATE TABLE创建一个具有给定名称的表。如果已存在具有相同名称的表或视图,则会引发错误。您可以使用IF NOT EXISTS跳过错误。

内部表(Managed)

说明:
Hive会(或多或少地)控制着数据的生命周期。当删除一个内部表表时,Hive也会删除这个表中数据。
创建表时,默认情况下是内部表

外部表(External

因为表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
例子:

CREATE EXTERNAL TABLE page_view(viewTime INT, userid BIGINT,
     page_url STRING, referrer_url STRING,
     ip STRING COMMENT 'IP Address of the User',
     country STRING COMMENT 'country of origination')
 COMMENT 'This is the staging page view table'
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\054'
 STORED AS TEXTFILE
 LOCATION '<hdfs_location>';

说明:

  • EXTERNAL :关键字表示创建一个外部表
  • LOCATION :关键字表示该表指向存储数据的HDFS 位置

内部表和外部表功能比较

官网原文
在这里插入图片描述
翻译:
这意味着有许多功能仅适用于两种表类型之一,而另一种则不可用。这是一个不完整的清单:

  • ARCHIVE/UNARCHIVE/TRUNCATE/MERGE/CONCATENATE 仅适用于托管表
  • DROP 删除托管表的数据,而只删除外部表的元数据
  • ACID/Transactional 仅适用于托管表
  • 查询结果缓存仅适用于托管表
  • 外部表上只允许使用 RELY 约束
  • 某些物化视图功能仅适用于托管表

分区表

可以使用 PARTITIONED BY 子句创建分区表。一个表可以有一个或多个分区列,并且为分区列中的每个不同的值组合创建一个单独的数据目录。此外,可以使用 CLUSTERED BY 列对表或分区进行分桶,并且可以通过 SORT BY 列在该桶内对数据进行排序。这可以提高某些类型的查询的性能。

如果在创建分区表时收到此错误:“FAILED: Error in semantic analysis: Column repeating in partitioning columns”,则表示您正在尝试将分区列包含在表本身的数据中。您可能确实定义了该列。但是,您创建的分区创建了一个可以查询的伪列,因此您必须将表列重命名为其他名称(用户不应查询!)。

注意:分区字段不能是表中已经存在的数据字段,可以将分区字段看作表的伪列。

  • 创建分区表的例子
CREATE TABLE page_view(viewTime INT, userid BIGINT,
     page_url STRING, referrer_url STRING,
     ip STRING COMMENT 'IP Address of the User')
 COMMENT 'This is the page view table'
 PARTITIONED BY(dt STRING, country STRING)
 ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\t'
 STORED AS ORC;

说明:
以上语句创建了 page_view 表,其中包含 viewTime、userid、page_url、referrer_url 和 ip 列(包括评论)。

  • PARTITIONED BY : 表示创建分区表,如果使用多级分区的情况下是使用逗号‘,’隔开
  • ROW FORMAT DELIMITED FIELDS TERMINATED BY: 指定文件中的数据按照 \t 进行分割
  • STORED 指定存储方式

增加分区

alter table table_name add partition(day='20200404');

增加多个分区

alter table table_name add partition(day='20200405') partition(day='20200406'); 

删除分区

alter table table_name drop partition 
(day='20200406');

同时删除多个分区

alter table table_name drop partition 
(day='20200404'), partition(day='20200405'); 

查看分区表有多少分区

show partitions table_name; 

查看分区表结构

desc formatted table_name; 

分区修复

msck repair table table_name;

动态分区

分桶表

分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分。分桶是将数据集分解成更容易管理的若干部分的另一个技术。分区针对的是数据的存储路径;分桶针对的是数据文件

建表语句

create table test_bucket(
    id int,
    name string,
    age int
)
clustered by (age) into 4 buckets
-- 注意分桶字段只能是建表中已有的字段,
-- 而分区表的字段必须是建表中没有的字段
row format delimited
fields terminated by  ' ';
  • 分桶规则
    Hive 的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中
  • 注意事项:
    • 分桶表只能通过insert插入数据,load 装载数据是无效的
    • 分区针对的是数据的存储路径;分桶针对的是数据文件CSDN字体修改

修改表/分区/列

更改表

  • 重命名表
ALTER TABLE table_name RENAME TO new_table_name;
  • 更改表属性
ALTER TABLE table_name SET TBLPROPERTIES table_properties;
 
table_properties:
  : (property_name = property_value, property_name = property_value, ... )
  • 更改表注释
-- 更改表的注释,必须更改的comment属性TBLPROPERTIES:
ALTER TABLE table_name SET TBLPROPERTIES ('comment' = new_comment);
  • 更改表存储属性
ALTER TABLE table_name CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name, ...)]
  INTO num_buckets BUCKETS;

这些命令只会修改 Hive 的元数据,不会重新组织或重新格式化现有数据。用户应确保实际数据布局符合元数据定义。

更改分区

通过使用 ALTER TABLE 语句中的 PARTITION 子句,可以添加、重命名、交换(移动)、删除或(取消)归档分区,如下所述。要使元存储了解直接添加到 HDFS 的分区,您可以使用元存储检查命令 ( MSCK ),或者在 Amazon EMR 上,您可以使用 ALTER TABLE 的 RECOVER PARTITIONS 选项

  • 添加分区
ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [LOCATION 'location'][, PARTITION partition_spec [LOCATION 'location'], ...];
 
partition_spec:
  : (partition_column = partition_col_value, partition_column = partition_col_value, ...)

使用 ALTER TABLE ADD PARTITION 将分区添加到表中。仅当分区值是字符串时才应引用它们。该位置必须是数据文件所在的目录。(ADD PARTITION 更改表元数据,但不加载数据。如果分区位置不存在数据,查询将不会返回任何结果。)如果表的 partition_spec 已存在,则会引发错误。您可以使用 IF NOT EXISTS 跳过错误。

  • 例子
ALTER TABLE page_view ADD PARTITION (dt='2008-08-08', country='us') location '/path/to/us/part080808'
                          PARTITION (dt='2008-08-09', country='us') location '/path/to/us/part080809';

更改表或分区

  • 更改表/分区文件格式
ALTER TABLE table_name [PARTITION partition_spec] SET FILEFORMAT file_format;
  • 更改表/分区位置
ALTER TABLE table_name [PARTITION partition_spec] SET LOCATION "new location";

更改列

column change 命令只会修改 Hive 的元数据,不会修改数据。用户应确保表/分区的实际数据布局符合元数据定义。

  • 更改列名称/类型/位置/评论
ALTER TABLE table_name [PARTITION partition_spec] CHANGE [COLUMN] col_old_name col_new_name column_type
  [COMMENT col_comment] [FIRST|AFTER column_name] [CASCADE|RESTRICT];
  • 例子
CREATE TABLE test_change (a int, b int, c int);
 
// First change column a's name to a1.
ALTER TABLE test_change CHANGE a a1 INT;
 
// Next change column a1's name to a2, its data type to string, and put it after column b.
ALTER TABLE test_change CHANGE a1 a2 STRING AFTER b;
// The new table's structure is:  b int, a2 string, c int.
  
// Then change column c's name to c1, and put it as the first column.
ALTER TABLE test_change CHANGE c c1 INT FIRST;
// The new table's structure is:  c1 int, b int, a2 string.
  
// Add a comment to column a1
ALTER TABLE test_change CHANGE a1 a1 INT COMMENT 'this is column a1';
  • 替换/添加列
ALTER TABLE table_name 
  [PARTITION partition_spec]                 -- (Note: Hive 0.14.0 and later)
  ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
  [CASCADE|RESTRICT]                         -- (Note: Hive 1.1.0 and later)

DML 数据操作

将文件加载到表中(LOAD)

Hive 在将数据加载到表中时不会进行任何转换。加载操作目前是纯粹的复制/移动操作,将数据文件移动到与 Hive 表对应的位置。

语法

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
 
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)

load data:表示加载数据
local:表示从本地加载数据到 hive 表;否则从 HDFS 加载数据到 hive 表
inpath:表示加载数据的路径
overwrite:表示覆盖表中已有数据,否则表示追加
into table:表示加载到哪张表
tablename:表示具体的表
partition:表示上传到指定分区

概要

  • 文件路径可以是相对路径,也可以是本地路径
  • 加载到的目标可以是分区表,如果是分区表则必须指定所有分区列的值来指定表的特定分区
  • filepatch 可以引用文件(在这种情况下,Hive 会将文件移动到表中)或者它可以是目录(在这种情况下,Hive 会将该目录中的所有文件移动到表中)。在任何一种情况下,文件路径都会寻址一组文件。
  • 如果指定关键字 LOCAL,则:
    • load 命令将在本地文件系统中查找文件路径。如果指定了相对路径,它将相对于用户的当前工作目录进行解释。用户也可以为本地文件指定完整的 URI - 例如:file:///user/hive/project/data1
    • load 命令将尝试将文件路径寻址的所有文件复制到目标文件系统。通过查看表的位置属性来推断目标文件系统。然后将复制的数据文件移动到表中。
    • 注意:如果对 HiveServer2 实例运行此命令,则本地路径是指 HiveServer2 实例上的路径。HiveServer2 必须具有访问该文件的适当权限。
  • 如果未指定关键字 LOCAL,则 Hive 将使用filepath的完整 URI(如果指定),或者将应用以下规则:
    • 如果未指定方案或权限,Hive 将使用fs.default.name指定 Namenode URI 的 hadoop 配置变量中的方案和权限。
    • 如果路径不是绝对的,那么 Hive 将相对于/user/
      Hive 会将文件路径寻址的文件移动到表(或分区)中
    • 如果使用了 OVERWRITE 关键字,则目标表(或分区)的内容将被删除并替换为filepath引用的文件;否则文件路径引用的文件将被添加到表中。
  • 文件路径可以包含子目录,前提是每个文件都符合架构。
  • inputformat可以是任何 Hive 输入格式,例如文本、ORC 等。
  • serde可以是关联的 Hive SERDE。
  • inputformat和serde都区分大小写。

笔记

  • 文件路径不能包含子目录(Hive 3.0 或更高版本除外,如上所述)。
  • 如果没有给出关键字 LOCAL,则文件路径必须引用与表(或分区)位置相同的文件系统中的文件。
  • Hive 进行一些最小检查以确保正在加载的文件与目标表匹配。目前它检查如果表以序列文件格式存储,则正在加载的文件也是序列文件,反之亦然。
  • 在 0.13.0 ( HIVE-6048 )版本中修复了当文件名包含“+”字符时阻止加载文件的错误。
  • 如果您的数据文件被压缩,请阅读CompressedStorage 。

从查询中将数据插入Hive 表中(insert)

可以使用 insert 子句将查询结果插入到表中。

语法

Standard syntax:
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
 
Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1
[INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2]
[INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2] ...;
FROM from_statement
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1
[INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2]
[INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2] ...;
 
Hive extension (dynamic partition inserts):
INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;
INSERT INTO TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;

概要

  • INSERT OVERWRITE 将覆盖表或分区中的任何现有数据

    • 除非IF NOT EXISTS为分区提供(从 Hive 0.9.0 开始)。
    • 从 Hive 2.3.0 ( HIVE-15880 ) 开始,如果表具有TBLPROPERTIES (“auto.purge”=“true”),则当对表运行 INSERT OVERWRITE 查询时,表的先前数据不会移动到垃圾箱。此功能仅适用于托管表(请参阅托管表),并在“auto.purge”属性未设置或设置为 false 时关闭。
  • INSERT INTO 将追加到表或分区,保持现有数据不变。(注意:INSERT INTO 语法仅从 0.8 版开始可用。)

    • 从 Hive 0.13.0开始,可以通过使用 TBLPROPERTIES (“immutable”=“true”)创建表来使其不可变。默认值为“不可变”=“假”。如果任何数据已经存在,则 INSERT INTO 行为将被禁止到不可变表中,但如果不可变表为空,则 INSERT INTO 仍然有效。INSERT OVERWRITE 的行为不受“不可变”表属性的影响。由于将数据加载到其中的脚本错误地运行了多次,因此可以防止不可变表发生意外更新。第一次插入不可变表成功,后续插入失败,导致表中只有一组数据,
  • 可以对表或分区进行插入。如果表是分区的,则必须通过指定所有分区列的值来指定表的特定分区。如果hive.typecheck.on.insert设置为 true,则这些值将被验证、转换和规范化以符合其列类型(Hive 0.12.0及更高版本)。

  • 可以在同一个查询中指定多个插入子句(也称为多表插入)。

  • 每个 select 语句的输出都被写入所选的表(或分区)。目前 OVERWRITE 关键字是强制性的,意味着所选表或分区的内容将替换为相应选择语句的输出。

  • 输出格式和序列化类由表的元数据确定(通过表上的 DDL 命令指定)。

  • 从Hive 0.14开始,如果表具有实现 AcidOutputFormat 的 OutputFormat,并且系统配置为使用实现 ACID 的事务管理器,则该表的 INSERT OVERWRITE 将被禁用。这是为了避免用户无意中覆盖交易历史。通过使用TRUNCATE TABLE(对于非分区表)或DROP PARTITION后跟 INSERT INTO可以实现相同的功能。

  • 从 Hive 1.1.0开始,TABLE 关键字是可选的。

  • 从 Hive 1.2.0开始,每个 INSERT INTO T 都可以采用类似于 INSERT INTO T (z, x, c1) 的列列表。有关示例,请参阅 HIVE-9481的描述。

  • 从 Hive 3.1.0 开始,不允许在完整的 CRUD ACID 表上使用 UNION ALL 的源插入覆盖。

笔记

  • 多表插入最大限度地减少了所需的数据扫描次数。Hive 可以通过对输入数据进行一次扫描(并应用不同的查询运算符)将数据插入到多个表中。
  • 从 Hive 0.13.0开始,select 语句可以包含一个或多个公共表表达式 (CTE),如 SELECT 语法中所示。有关示例,请参阅 公用表表达式。

动态分区插入

在动态分区插入中,用户可以给出部分分区规范,即只在 PARTITION 子句中指定分区列名列表。列值是可选的。如果给定了一个分区列值,我们称其为静态分区,否则为动态分区。每个动态分区列都有一个来自 select 语句的相应输入列。这意味着动态分区的创建是由输入列的值决定的。动态分区列必须在 SELECT 语句中的列中最后指定,并且与它们在 PARTITION() 子句中出现的顺序相同。从 Hive 3.0.0 开始(HIVE-19083) 不需要指定动态分区列。如果未指定,Hive 将自动生成分区规范。
在 Hive 0.9.0 之前默认禁用动态分区插入,在 Hive 0.9.0及更高版本中默认启用。这些是动态分区插入的相关配置属性:

配置属性默认值笔记
hive.error.on.empty.partitionfalse如果动态分区插入产生空结果是否抛出异常
hive.exec.dynamic.partitiontrue需要设置true为启用动态分区插入
hive.exec.dynamic.partition.modestrict模式下,strict用户必须至少指定一个静态分区,以防用户不小心覆盖了所有分区,nonstrict模式下所有分区都允许是动态的
hive.exec.max.created.files100000MapReduce 作业中所有映射器/缩减器创建的 HDFS 文件的最大数量
hive.exec.max.dynamic.partitions1000总共允许创建的最大动态分区数
hive.exec.max.dynamic.partitions.pernode100每个 mapper/reducer 节点允许创建的最大动态分区数

例子

FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country)
       SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.cnt

此处country分区将由SELECT子句中的最后一列动态创建(即pvs.cnt)。请注意,未使用该名称。在nonstrict模式下,dt分区也可以动态创建。

通过查询将数据写入文件系统

通过使用上述语法的轻微变化,可以将查询结果插入到文件系统目录中:

语法

Standard syntax:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
  [ROW FORMAT row_format] [STORED AS file_format] (Note: Only available starting with Hive 0.11.0)
  SELECT ... FROM ...
 
Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...
 
  
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: Only available starting with Hive 0.13)

概要

  • 目录可以是完整的 URI。如果未指定方案或权限,Hive 将使用fs.default.name指定 Namenode URI 的 hadoop 配置变量中的方案和权限。
  • 如果使用 LOCAL 关键字,Hive 会将数据写入本地文件系统上的目录。
  • 写入文件系统的数据被序列化为文本,列由 ^A 分隔,行由换行符分隔。如果任何列不是原始类型,则将这些列序列化为 JSON 格式。

笔记

  • 对目录、本地目录和表(或分区)的 INSERT OVERWRITE 语句都可以在同一个查询中一起使用。
  • 对 HDFS 文件系统目录的 INSERT OVERWRITE 语句是从 Hive 提取大量数据的最佳方式。Hive 可以从 map-reduce 作业中并行写入 HDFS 目录。
  • 如您所料,该目录是 OVERWRITten;换句话说,如果指定的路径存在,它将被破坏并替换为输出。
  • 从 Hive 0.11.0 开始,可以指定使用的分隔符;在早期版本中,它始终是 ^A 字符 (\001)。但是,仅 Hive 版本 0.11.0 到 1.1.0 中的 - - - LOCAL 写入支持自定义分隔符 - 此错误已在版本 1.2.0 中修复(请参阅 HIVE-5672)。
  • 在Hive 0.14中,插入符合ACID的表将在选择和插入期间停用矢量化。这将自动完成。插入了数据的 ACID 表仍然可以使用向量化进行查询。

从SQL向表中插入值

INSERT…VALUES 语句可用于直接从 SQL 向表中插入数据。

语法


Standard Syntax:
INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...]
  
Where values_row is:
( value [, value ...] )
where a value is either null or any valid SQL literal

概要

  • VALUES 子句中列出的每一行都插入到表tablename中。
  • 必须为表中的每一列提供值。尚不支持允许用户仅将值插入某些列的标准 SQL 语法。为了模仿标准 SQL,可以为用户不希望为其分配值的列提供空值。
  • 动态分区的支持方式与INSERT…SELECT相同。
  • 如果插入的表支持ACID并且正在使用支持 ACID 的事务管理器,则此操作将在成功完成后自动提交。
  • Hive 不支持复杂类型(数组、映射、结构、联合)的文字,因此无法在 INSERT INTO…VALUES 子句中使用它们。这意味着用户不能使用 INSERT INTO…VALUES 子句将数据插入到复杂数据类型的列中。

例子

CREATE TABLE students (name VARCHAR(64), age INT, gpa DECIMAL(3, 2))
  CLUSTERED BY (age) INTO 2 BUCKETS STORED AS ORC;
 
INSERT INTO TABLE students
  VALUES ('fred flintstone', 35, 1.28), ('barney rubble', 32, 2.32);
 
 
CREATE TABLE pageviews (userid VARCHAR(64), link STRING, came_from STRING)
  PARTITIONED BY (datestamp STRING) CLUSTERED BY (userid) INTO 256 BUCKETS STORED AS ORC;
 
INSERT INTO TABLE pageviews PARTITION (datestamp = '2014-09-23')
  VALUES ('jsmith', 'mail.com', 'sports.com'), ('jdoe', 'mail.com', null);
 
INSERT INTO TABLE pageviews PARTITION (datestamp)
  VALUES ('tjohnson', 'sports.com', 'finance.com', '2014-09-23'), ('tlee', 'finance.com', null, '2014-09-21');
  
INSERT INTO TABLE pageviews
  VALUES ('tjohnson', 'sports.com', 'finance.com', '2014-09-23'), ('tlee', 'finance.com', null, '2014-09-21');

更新

语法

Standard Syntax:
UPDATE tablename SET column = value [, column = value ...] [WHERE expression]

概要

  • 引用的列必须是正在更新的表的列。
  • 分配的值必须是 Hive 在 select 子句中支持的表达式。因此支持算术运算符、UDF、强制转换、文字等。不支持子查询。
  • 只有匹配 WHERE 子句的行才会被更新。
  • 无法更新分区列。
  • 无法更新存储桶列。
  • 在 Hive 0.14 中,成功完成此操作后,更改将自动提交。

笔记

  • 更新操作将关闭矢量化。这是自动的,不需要用户采取任何行动。非更新操作不受影响。更新后的表仍然可以使用矢量化进行查询。
  • 在版本 0.14 中,建议您在进行更新时设置 hive.optimize.sort.dynamic.partition =false,因为这会产生更有效的执行计划。

删除

语法:


Standard Syntax:
DELETE FROM tablename [WHERE expression]

合并

语法

Standard Syntax:
MERGE INTO <target table> AS T USING <source expression/table> AS S
ON <boolean expression1>
WHEN MATCHED [AND <boolean expression2>] THEN UPDATE SET <set clause list>
WHEN MATCHED [AND <boolean expression3>] THEN DELETE
WHEN NOT MATCHED [AND <boolean expression4>] THEN INSERT VALUES<value list>

数据导出

将查询结果导入到本地

insert overwrite local directory 
'filepath' select * from table_name; 

将查询结果导入到HDFS

insert overwrite directory 'filepath'  ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'  select * from table_name;

将查询结果格式化存储

insert overwrite local directory 'filepath' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from table_name; 

存储格式

列式存储和行式存储

1) 行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快
2) 列存储的特点
因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。

行式存储和列式存储的分别使用场景和优缺点

当查询结果为一整行的时候,行存储效率会高一些;当查询表中某几列时,列存储的效率会更高。 在对数据的压缩方面,列存储比行存储更有优势,所以列存储占用空间相对小一些

TEXTFILE【行式存储】

优缺点:

TEXTFILE 即正常的文本格式,存储方式为行存储,数据不做压缩,磁盘开销大,数据解析开销大,数据不支持分片,数据加载导入方式可以通过LOAD和INSERT两种方式加载数据。是Hive默认文件存储格式

耗费存储空间,I/O性能较低;Hive不进行数据切分合并,不能进行并行操作,查询效率低


TEXTFILE 即正常的文本格式,存储方式为行存储,数据不做压缩,磁盘开销大,数据解析开销大,数据不支持分片,数据加载导入方式可以通过LOAD和INSERT两种方式加载数据。是Hive默认文件存储格式,因为大多数情况下源数据文件都是以text文件格式保存(便于查看验数和防止乱码)。此种格式的表文件在HDFS上是明文,可用hadoop fs -cat命令查看,从HDFS上get下来后也可以直接读取。

TEXTFILE 存储文件默认每一行就是一条记录,可以指定任意的分隔符进行字段间的分割。但这个格式无压缩,需要的存储空间很大。虽然可结合Gzip、Bzip2、Snappy等使用,使用这种方式,Hive不会对数据进行切分,从而无法对数据进行并行操作。

SEQUENCEFILE【行式存储】

优缺点:

  • 存储特点: 二进制文件,以<key,value>的形式序列化到文件中

  • 存储方式:行存储

  • 压缩:

    SequenceFIle 的内部格式取决于是否启用压缩,如果是压缩,则又可以分为记录压缩和块压缩。

    无压缩(NONE):如果没有启用压缩(默认设置)那么每个记录就由它的记录长度(字节数)、键的长度,键和值组成。长度字段为 4 字节。

    记录压缩(RECORD):记录压缩格式与无压缩格式基本相同,不同的是值字节是用定义在头部的编码器来压缩。注意:键是不压缩的。

    块压缩(BLOCK):块压缩一次压缩多个记录,因此它比记录压缩更紧凑,而且一般优先选择。当记录的字节数达到最小大小,才会添加到块。该最小值由 io.seqfile.compress.blocksize 中的属性定义。默认值是 1000000 字节。格式为记录数、键长度、键、值长度、值。Record 压缩率低,一般使用BLOCK压缩。优势是文件和Hadoop api中的mapfile是相互兼容的。

  • 特点:可分割,压缩,优化磁盘利用率和I/O;可并行操作数据,查询效率高。


SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以<key,value>的形式序列化到文件中。这种二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使用value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。

SequenceFile支持三种压缩选择:NONE, RECORD, BLOCK。 Record压缩率低,一般建议使用BLOCK压缩。 SequenceFile最重要的优点就是Hadoop原生支持较好,有API,但除此之外平平无奇,实际生产中不会使用。

ORC【列式存储】(重点关注)⭐⭐⭐⭐⭐

  • 存储模式:按列存储,所有列存在一个文件中,
  • 每个ORC文件首先会被横向切分成多个Stripe,而每个Stripe内部以列存储,所有的列存储在一个文件中,而且每个stripe默认的大小是250MB,相对于RCFile默认的行组大小是4MB,所以比RCFile更高效Postscripts中存储该表的行数,压缩参数,压缩大小,列等信息;Stripe Footer中包含该stripe的统计结果,包括Max,Min,count等信息;FileFooter中包含该表的统计结果,以及各个Stripe的位置信息;IndexData中保存了该stripe上数据的位置信息,总行数等信息;RowData以stream的形式保存了数据的具体信息

ORCFile是RCFile的优化版本,hive特有的数据存储格式,存储方式为行列存储,具体操作是将数据按照行分块,每个块按照列存储,其中每个块都存储有一个索引,自身支持切片,数据加载导入方式可以通过INSERT方式加载数据。

自身支持两种压缩ZLIB和SNAPPY,其中ZLIB压缩率比较高,常用于数据仓库的ODS层,SNAPPY压缩和解压的速度比较快,常用于数据仓库的DW层

相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势。
在这里插入图片描述
1) Index Data:一个轻量级的 index,默认是每隔 1W 行做一个索引。这里做的索引应该只是记录某行的各字段在 Row Data 中的 offset。
2) Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个 Stream 来存储。
3) Stripe Footer:存的是各个 Stream 的类型,长度等信息。
每个文件有一个 File Footer,这里面存的是每个 Stripe 的行数,每个 Column 的数据类型信息等;每个文件的尾部是一个 PostScript,这里面记录了整个文件的压缩类型以及
FileFooter 的长度信息等。在读取文件时,会 seek 到文件尾部读 PostScript,从里面解析到
File Footer 长度,再读 FileFooter,从里面解析到各个 Stripe 信息,再读各个 Stripe,即从后往前读。

PARQUET【列式存储】(重点关注)⭐⭐⭐⭐⭐

  • 存储模式:按列存储,Parquet文件是以二进制方式存储的,不可以直接读取和修改的,文件是自解析的,文件中包括该文件的数据和元数据
  • 存储结构:行组(Row Group):按照行将数据物理上划分为多个单元,每一个行组包含一定的行数,在一个HDFS文件中至少存储一个行组,Parquet读写的时候会将整个行组缓存在内存中,所以如果每一个行组的大小是由内存大的小决定的

Parquet 文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此 Parquet 格式文件是自解析的。
(1) 行组(Row Group):每一个行组包含一定的行数,在一个 HDFS 文件中至少存储一个行组,类似于 orc 的 stripe 的概念。
(2) 列块(Column Chunk):在一个行组中每一列保存在一个列块中,行组中的所有列连续的存储在这个行组文件中。一个列块中的值都是相同类型的,不同的列块可能使用不同的算法进行压缩。
(3) 页(Page):每一个列块划分为多个页,一个页是最小的编码的单位,在同一个列块的不同页可能使用不同的编码方式。
通常情况下,在存储 Parquet 数据的时候会按照 Block 大小设置行组的大小,由于一般情况下每一个 Mapper 任务处理数据的最小单位是一个 Block,这样可以把每一个行组由一个 Mapper 任务处理,增大任务执行并行度。Parquet 文件的格式。

在这里插入图片描述
上图展示了一个 Parquet 文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的 Magic Code,用于校验它是否是一个 Parquet 文件,Footer length 记录了文件元数据的大小,通过该值和文件长度可以计算出元数据的偏移量,文件的元数据中包括每一个行组的元数据信息和该文件存储数据的 Schema 信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在 Parquet 中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字典页,索引页用来存储当前行组下该列的索引,目前 Parquet 中还不支持索引

AVRO

Avro是一种用于支持数据密集型的二进制文件格式。它的文件格式更为紧凑,若要读取大量数据时,Avro能够提供更好的序列化和反序列化性能。并且Avro数据文件天生是带Schema定义的,所以它不需要开发者在API 级别实现自己的Writable对象。动态语言友好,Avro提供的机制使动态语言可以方便地处理Avro数据。最近多个Hadoop 子项目都支持Avro 数据格式,如Pig 、Hive、Flume、Sqoop和Hcatalog。

Avro据说设计出来的最大目的是为了满足模式演进,也是早年间诞生的一种数据格式,使用的也不多。

RCFILE

一种行列存储相结合的存储方式,基本被ORCFILE替代

JSONFILE

存储为Json文件格式

运算符和函数

官方文档:内置运算符和函数

其他

Hive的UDF、UDAF、UDTF函数有什么区别

(1)UDF(User-Defined-Function)
单行进入,单行输出

(2)UDAF(User-Defined Aggregation Function)
聚集函数,多行进入,单行输出

(3)UDTF(User-Defined Table-Generating Functions)
一进多出

如何自定义UDF,UDAF,UDTF 函数

  • 自定义UDF函数
    • 继承org.apache.hadoop.hive.ql.UDF函数;
    • 重写evaluate方法,evaluate方法支持重载。
  • 自定义UDAF函数
    • 必须继承org.apache.hadoop.hive.ql.exec.UDAF(函数类继承)和org.apache.hadoop.hive.ql.exec.UDAFEvaluator(内部类Evaluator实现UDAFEvaluator接口);
    • 重写Evaluator方法时需要实现 init、iterate、terminatePartial、merge、terminate这几个函数:
      • init():类似于构造函数,用于UDAF的初始化
      • iterate():接收传入的参数,并进行内部的轮转,返回boolean
      • terminatePartial():无参数,其为iterate函数轮转结束后,返回轮转数据,类似于hadoop的Combiner
      • merge():接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean
      • terminate():返回最终的聚集函数结果
  • 自定义UDTF函数
    • 继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF函数
    • 重写实现initialize, process, close三个方法。
      • UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
      • 初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中,每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
      • 最后close()方法调用,对需要清理的方法进行清理。

Like和RLike

使用LIKE运算选择类似的值,% 代表零个或多个字符(任意个字符)。 _ 代表一个字符。

RLIKE子句是Hive中这个功能的一个扩展,其可以通过Java的正则表达式这个更强大的语言来指定匹配条件。

having与where不同点

(1)where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。

(2)where后面不能写分组函数,而having后面可以使用分组函数。

(3)having只用于group by分组统计语句。

Hive 索引(不推荐使用)

Hive不支持主键或者外键。并且Hive索引提供的功能很有限,效率也并不高

适用于不更新的静态字段。以免总是重建索引数据。每次建立、更新数据后,都要重建索引以构建索引表。

hive在指定列上建立索引,会产生一张索引表(Hive的一张物理表),里面的字段包括:索引列的值、该值对应的HDFS文件路径、该值在文件中的偏移量。

Hive中每次有数据时需要及时更新索引,相当于重建一个新表,否则会影响数据查询的效率和准确性

HSQL转换为Map Reduce的过程

  • SQL Parser:
    Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象 语法树AST Tree;

  • Semantic Analyzer:
    遍历AST Tree,抽象出查询的基本组成单元Query Block;

  • Logical plan:
    遍历Query Block,翻译为执行操作树Operator Tree;

  • Logical plan optimizer:
    逻辑层优化器进行Operator Tree变换,合并不必要的Reduce Sink Operator,减少shuffle数据量;

  • Physical plan:
    遍历Operator Tree,翻译为Map Reduce任务;

  • Logical plan optimizer:
    物理层优化器进行Map Reduce任务的变换,生成最终的执行计划;

提交一条SQL到Hive后,Hive的执行流程是怎样的?

在这里插入图片描述

SQL Statement:SQL语句
Parser:解析器
Relational Expression:关系表达式
Optimizer:优化器
Metadata:元数据
Statistics:统计
Execution Plan:执行计划
Execution Engine:执行引擎
Query Result:查询结果

1、将SQL提交给了解析器。
2、解析器根据SQL生产抽象语法树,同时与元数据进行交互生成逻辑执行计划。
3、优化器对逻辑执行计划进行优化,最终生成物理执行计划交给执行引擎进行执行。
延申:一条具体的SQL执行计划
在这里插入图片描述

解析器会把这个SQL解析成一个个operator(hive解析后的最小单元、一个operator对应一个MR的执行任务),Hive实现了优化器对这些operator的顺序进行优化,提高查询效率。

Hive的两张表关联,使用Map Reduce怎么实现?

如果其中有一张表为小表,直接使用map端join的方式进行聚合。
如果两张都是大表,那么采用联合key,联合key的第一个组成部分是join on中的公共字段,第二部分是一个flog.

Hive的表存储模型有哪些

Hive几种基本表类型:内部表、外部表、分区表、分桶表

  • 内部表:
    内部表:内部表的数据,会存放在 HDFS 中的特定的位置中,我们在安装Hive的配置中是在/hive/warehouse。;当删除表时,数据文件也会一并删除;适用于临时创建的中间表

  • 外部表:
    外部表:适用于想要在 Hive 之外使用表的数据的情况==.当你删除 External Table 时,只是删除了表的元数据,它的数据并没有被删除==。适用于数据多部门共享。建表时使用create external table。 指定external关键字即可。

  • 分区表:
    分区表:分区表创建表的时候需要指定分区字段,分区字段与普通字段的区别:分区字段会在HDFS表目录下生成一个分区字段名称的目录,而普通字段则不会,查询的时候可以当成普通字段来使用,一般不直接和业务直接相关。
    分区会创建物理目录,并且可以具有子目录(通常会按照时间、地区分区),目录名以=创建,分区名会作为表中的伪列,这样通过where字句中加入分区的限制可以在仅扫描对应子目录下的数据。通过partitioned by(field1 type,…)

  • 分桶表:
    分桶表:将内部表,外部表和分区表进一步组织成桶表,可以将表的列通过Hash算法进一步分解成不同的文件存储。
    分桶可以继续在分区的基础上再划分小表,分桶根据哈希值来确定数据的分布(即MapReducer中的分区!),比如分区下的一部分数据可以根据分桶再分为多个桶,这样在查询时先计算对应列的哈希值并计算桶号,只需要扫描对应桶中的数据即可。

分区表和分桶表的区别

  • 分区表:
    分区表实际上是在表的目录下在以分区命名,建子目录
    作用:进行分区裁剪,避免全表扫描,减少Map Reduce处理的数据量,提高效率
    一般在公司的hive中,所有的表基本上都是分区表,通常按日期分区、地域分区
    分区表在使用的时候记得加上分区字段
    分区也不是越多越好,一般不超过3级,根据实际业务衡量

  • 动态分区表:
    有的时候我们原始表中的数据里面包含了 ‘‘日期字段 dt’’,我们需要根据dt中不同的日期,分为不同的分区,将原始表改造成分区表。
    hive默认不开启动态分区
    动态分区:根据数据中某几列的不同的取值 划分 不同的分区

  • 分桶表:
    分桶是相对分区进行更细粒度的划分。
    分桶将整个数据内容安装某列属性值得hash值进行区分,如要按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。
    如取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件

Hive内部表和外部表的区别?

创建表时:创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。

删除表时:在删除表的时候,内部表的元数据和数据会被一起删除, 而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。

Hive 中的文件存储格式

Hive支持的存储数据的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。

  1. 行存储的特点
    查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。

  2. 列存储的特点
    因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。

TEXTFILE和SEQUENCEFILE的存储格式都是基于行存储的;

ORC和PARQUET是基于列式存储的。

  1. Text File(文本格式文件(行式存储))
    默认格式,存储方式为行存储,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,压缩后的文件不支持split,Hive不会对数据进行切分,从而无法对数据进行并行操作。并且在反序列化过程中,必须逐个字符判断是不是分隔符和行结束符,因此反序列化开销会比Sequence File高几十倍。

  2. Sequence File(二进制序列化文件(行式存储))
    Sequence File是Hadoop API提供的一种二进制文件支持,存储方式为行存储,其具有使用方便、可分割、可压缩的特点。

Sequence File支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。
优势是文件和Hadoop API中的Map File是相互兼容的

  1. ORC File (列式存储)
    存储方式:数据按行分块 每块按照列存储。
    压缩快、快速列存取。
    效率比RC file高,是RC File的改良版本。

  2. Parquet
    Parquet 是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。
    是一个面向列的二进制文件格式,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。Parquet对于大型查询的类型是高效的。对于扫描特定表格中的特定列的查询,Parquet特别有用。Parquet一般使用Snappy、Gzip压缩,默认是Snappy。

  3. 总结

相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。

数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势。

Hive有哪些保存元数据的方式,有什么特点

内存数据库derby,按照小,但是数据存在内存,不稳定

MySQL数据库,数据存储模式可以自己设置,持久化号,查看方便

hive中 Sort By,Order By,Cluster By,Distrbute By各代表什么意思?

  • order by:
    会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)。只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
  • sort by:
    分区内有序,其在数据进入reducer前完成排序。每个reducer内部进行排序,对全局结果集来说不是排序。随机分区,防止数据倾斜。
  • distribute by:
    数据分发 按照指定的字段对数据进行划分输出到不同的reduce中。默认是采用hash算法+取余数的方式。
  • cluster by:
    除了具有 distribute by 的功能外还兼具 sort by 的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。

总结:

  1. order by 是全局排序,可能性能会比较差;
  2. sort by 分区内有序,往往配合distribute by来确定该分区都有那些数据;
  3. distribute by 确定了数据分发的规则,满足相同条件的数据被分发到一个reducer;默认是采用hash算法+取余数的方式。
  4. cluster by 当distribute by和sort by 字段相同时,可以使用cluster by 代替distribute by和sort by,但是cluster by默认是升序,不能指定排序方向;
  5. sort by limit 相当于每个reduce 的数据limit 之后,进行order by 然后再limit ;

数据倾斜

什么时数据倾斜

数据倾斜在MapReduce计算框架中经常发生。通俗理解,该现象指的是在整个计算过程中,大量相同的key被分配到了同一个任务上,造成“一个人累死、其他人闲死”的状况,这违背了分布式计算的初衷,使得整体的执行效率十分低下。

hive 底层采用的是MapReduce计算框架,需要清楚了解MapReduce的工作原理和具体的执行步骤

如何解决数据倾斜

了解了MapReduce的解析原理。日常工作中数据倾斜主要发生在Reduce阶段,而很少发生在 Map阶段,其原因是Map端的数据倾斜一般是由于HDFS数据存储不均匀造成的(公司的日志存储几乎都是均匀分块存储,每个文件大小基本固定),而Reduce阶段的数据倾斜几乎都是因为分析师没有考虑到某种key值数据量偏多的情况而导致的。
参考:参考博客地址
参考:参考博客地址

Hive的优化

  • 真的需要扫描这么多分区么?比如对于销售明细事务表来说,扫描一年的分区和扫描一周的分区所带来的计算、IO开销完全是两个量级,所耗费的时间肯定也是不同的。笔者并不是说不能扫描一年的分区,而是希望开发人员需要仔细考虑业务需求,尽量不浪费计算和存储资源,毕竟大数据也不是毫无代价的。
  • 尽量不要使用select*from your_table这样的方式,用到哪些列就指定哪些列,如select col1,col2from your_table。另外,where条件中也尽量添加过滤条件,以去掉无关的数据行,从而减少整个MapReduce任务中需要处理、分发的数据量。
  • 输入文件不要是大量的小文件。Hive的默认Input Split是128MB(可配置),小文件可先合并成大文件。

group by引起的倾斜优化

group by引起的倾斜主要是输入数据行按照group by列分布不均匀引起的,比如,假设按照供应商对销售明细事实表来统计订单数,那么部分大供应商的订单量显然非常多,而多数供应商的订单量就一般,由于group by的时候是按照供应商的ID分发到每个Reduce Task,那么此时分配到大供应商的Reduce Task就分配了更多的订单,从而导致数据倾斜。
对于group by引起的倾斜,优化措施非常简单,只需设置下面参数即可:

set hive.map.aggr = true
set hive.groupby.skewindata=true

此时Hive在数据倾斜的时候会进行负载均衡,生成的查询计划会有两个MapReduce Job。第一个MapReduce Job中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作并输出结果,这样处理的结果是相同的GroupBy Key有可能被分布到不同的Reduce中,从而达到负载均衡的目的;第二个MapReduce Job再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

count distinct优化

在Hive开发过程中,应该小心使用count distinct,因为很容易引起性能问题,比如下面的SQL:

select count(distinct user) from some_table;

由于必须去重,因此Hive将会把Map阶段的输出全部分布到一个Reduce Task上,此时很容易引起性能问题。对于这种情况,可以通过先group by再count的方式来优化,优化后的SQL如下:

select count(*)
from
(   select user
    from some_table
    group by user
) tmp;

其原理为:利用group by去重,再统计group by的行数目。

大表join小表优化

MAPJOIN 当一个大表和一个或多个小表做JOIN时,最好使用MAPJOIN,性能比普通的JOIN要快很多。 另外,MAPJOIN 还能解决数据倾斜的问题。 MAPJOIN的基本原理是:在小数据量情况下,SQL会将用户指定的小表全部加载到执行JOIN操作的程序的内存中,从而加快JOIN的执行速度。
使用mapjoin将小表放入内存,在map端和大表逐一匹配。从而省去reduce。

select /*+MAPJOIN(b)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1

mapjoin的join发生在map阶段,join的join发生在reduce阶段,mapjoin可以提高效率

原文链接:https://blog.csdn.net/u012036736/article/details/84978689

大表join大表优化

https://blog.csdn.net/panfelix/article/details/107913560


  • MpaJoin
    在Reduce阶段完成join. 容易发生数据倾斜, 可以用Mapjoin把小表全部加载到内存中再map端进行join, 避免Reduce处理
  • 行列过滤:
    • 列处理: 在select中 ,只需要拿到需要的列 ,尽量使用分区过滤 ,防止全表扫描影响性能 ,少用Select *
    • 行处理: 在分区裁剪中 ,使用外表关联的时候 ,如果将副表的关联条件写在where后面 ,那么就会先进行全表关联 ,之后再过滤
  • 采用分区技术
  • 合理设置map数量
    • map的主要决定因素在于input的文件总个数 ,input的文件大小 ,集群设置的文件块大小
    • map的数量不是越多越好 ,如果有很多小文件,一个文件会有一个map任务 ,map的启动和初始化的时间远远大于逻辑处理时间 ,就会造成很大的资源浪费
    • 不是保证每个文件都是128MB就可以高枕无忧 ,如果这个文件只有一个或者两个字段 ,有着几千万的记录 ,如果map的逻辑还比较复杂 ,用一个map任务去做的话肯定耗时
    • 针对2 3的情况 ,我们的方法就是减少map和增加map数量
  • 合理设置reduce
    • 过多的reduce数量 ,会和map出现一样的情况 ,启动和初始化的reduce消耗时间和资源
    • 有多少个reduce数量 ,就会输出多个少个文件 ,如果这些小文件作为下一个任务的输入 ,那就会出现小文件过多的问题
    • 在设置reduce数量的时候保持两个原子: 处理数据量利用合适的reduce数量 ,单个reduce任务处理的数据量大小要合适
  • 压缩(选择快的): 设置map端输出 ,中间结果压缩 (不完全是解决数据倾斜问题 ,也会解决I/O读写和网络传输 ,能提高很多效率)
  • 开启map端的combiner(不营销业务逻辑): set hive.map.aggr = true
  • 开启JVM重用
  • 常用参数 输出合并小文件
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值