目录
[DDL(数据定义语言)](#DDL(数据定义语言))
[Hive 数据类型](#Hive 数据类型)
[Create Table Like:](#Create Table Like:)
[Create Table As Select (CTAS):](#Create Table As Select (CTAS):)
[方式 1:静态添加分区(手动指定分区,适用于已有数据文件)](#方式 1:静态添加分区(手动指定分区,适用于已有数据文件))
[方式 2:动态添加分区(插入数据时自动创建,适用于新增数据)](#方式 2:动态添加分区(插入数据时自动创建,适用于新增数据))
[DQL(数据查询语言)](#DQL(数据查询语言))
[order by](#order by)
[sort by](#sort by)
[distribute by](#distribute by)
[cluster by](#cluster by)
DDL(数据定义语言)
Hive 数据类型
data_type
: primitive_type --基本数据类型
| array_type 数组
| map_type 键值对类型
| struct_type 结构体类型(类似于Java语言中的只有属性没有getters和setters方法的实体类)
| 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)
基本数据类型
|--------------|---------------------|---------------|
| 类型名称 | 描述 | 举例 |
| boolean | true/false | true |
| tinyint | 1字节的有符号整数 | 1 |
| smallint | 2字节的有符号整数 | 1 |
| ==int== | 4字节的有符号整数 | 1 |
| ==bigint== | 8字节的有符号整数 | 1 |
| float | 4字节单精度浮点数 | 1.0 |
| ==double== | 8字节单精度浮点数 | 1.0 |
| ==string== | 字符串(不设长度) | "gtjin" |
| varchar | 字符串(1-65355长度,超长截断) | "geekmooc.cn" |
| timestamp | 时间戳 | 161243654 |
| date | 日期 | 20211110 |
复合数据类型
|--------------|----------------------------------|-------------------|
| 类型名称 | 描述 | 举例 |
| array | 一组有序的字段,字段类型必须相同 array(元素1,元素2) | Array(1,2,3) |
| map | 一组无序的键值对 map(k1,v1,k2,v2) | Map('a',1,'b',2) |
| struct | 一组命名的字段,字段类型可以不同 struct(元素1,元素2) | Struct('a',1,2,0) |
array 字段的元素访问方式:
-
下标获取元素,下标从0开始
-
获取第一个元素: array[0]
map 字段的元素访问方式
-
通过键获取值
-
获取a这个key对应的value:map['a']
struct 字段的元素获取方式
-
定义一个字段c的类型为struct{a int;b string}
-
获取a和b的值:使用c.a 和c.b 获取其中的元素值
-
这里可以把这种类型看成是一个对象
sql
create table complex(
col1 array<int>,
col2 map<string,int>,
col3 struct <a:string,b:int,c:double>
)
数据库实例操作
创建数据库
sql
CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path]
[WITH DBPROPERTIES (property_name=property_value, ...)];
if not exists:作用是如果该数据库实例已经存在则不存在,反之才创建。
在hive中创建的数据库实例在hdfs上默认被放在hive.metastore.warehouse.dir参数指定的hdfs路
径下:
XML
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive_remote/warehouse</value>
</property>
查看数据库实例
show 的使用
语法格式
sql
SHOW DATABASES [LIKE ``'identifier_with_wildcards'``];
例子
sql
# 查询数据库实例名称以hivedb开头
hive> show databases like 'hivedb*';
# 查询数据库实例名称包含db关键词的:
hive> show databases like '*db*';
# 切换数据库
hive> use hivedb1;
hive> show tables;
DESCRIBE 的使用
语法格式(小写也能使用)
sql
DESCRIBE DATABASE [EXTENDED] db_name;
或者
DESC DATABASE [EXTENDED] db_name;
EXTENDED参数用于展示数据库实例的详细信息
修改数据库
语法格式
sql
alter database database_name set dbproperties (property_name=property_value,
...);
#修改数据的所有者,或所属角色
alter database database_name set owner [user|role] user_or_role;
#修改指定数据库实例在hdfs上位置
alter database database_name set location hdfs_path;
删除数据库
语法格式
sql
drop database [if exists] database_name [restrict|cascade];
**cascade:**当数据库实例中有数据,可以采用cascade命令,进行强制删除。
表操作
完整的 DDL 建表语法规则
sql
create [temporary] [external] table [if not exists] [db_name.]table_name
[(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, ...)
on ((col_value, col_value, ...), (col_value, col_value, ...), ...)
[stored as directories]
[
[row format row_format] -- 设置各种分隔符
[stored as file_format] --hdfs上存储时的文件格式
| stored by 'storage.handler.class.name' [with serdeproperties (...)]
]
[location hdfs_path] --hdfs上的位置
[tblproperties (property_name=property_value, ...)] --表的属性
[as select_statement]; -- 查询子句
创建表
sql
create table person(
id int comment "唯一标识id",
name string comment "名称",
likes array<string> comment "爱好",
address map<string,string> comment "地址"
)
row format delimited
fields terminated by ","
collection items terminated by "-"
map keys terminated by ":"
lines terminated by "\n";
默认分隔符
| 分隔符类型 | 默认值(ASCII 控制字符) | 对应键盘操作 | 配置参数(修改全局默认用) | 作用说明 |
| 字段分隔符 | \001(Octal)/ ^A | Ctrl + A | hive.default.field.delim | 拆分一行数据中的不同列(如 id、name、hobby 之间的分隔) |
| 集合元素分隔符 | \002(Octal)/ ^B | Ctrl + B | hive.default.collection.item.delim | 拆分 Array/Struct 等集合类型的内部元素(如 hobby 数组中 "lol-book-movie" 的 - 对应位) |
| Map 键值分隔符 | \003(Octal)/ ^C | Ctrl + C | hive.default.mapkey.delim | 拆分 Map 类型中 Key 和 Value(如 addr 中 "beijing:xisanqi" 的 : 对应位) |
| 行分隔符 | \n(换行符) | 回车键 | 无(无需配置,默认就是换行) | 拆分不同行的数据(如第一行和第二行的分隔) |
| 桶表 Hash 分隔符 | \004(Octal)/ ^D |
Ctrl + D | 无(极少修改) | 桶表中用于 Hash 分桶的分隔符 |
|---|
- 不可见性:这些默认值是 ASCII 控制字符,在文本编辑器 / 终端中无法直接显示,因此你用逗号 / 短横线 / 冒号分隔的数据,Hive 无法识别(会导致字段解析为 NULL);
- 优先级规则 :表级别显式指定(
ROW FORMAT DELIMITED)> 全局配置参数修改 > Hive 原生默认值;
使用已有表建表
Create Table Like:
只创建相同结构的空表,没有具体的表中的数据。
sql
create [temporary] [external] table [if not exists] [db_name.]table_name
like existing_table_or_view_name [location hdfs_path];
Create Table As Select (CTAS):
基于 SELECT 查询的结果,自动创建新表并将查询数据直接写入新表。
sql
-- 基础语法
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] 新表名
[COMMENT '表注释']
[PARTITIONED BY (分区字段 类型, ...)] -- 可选:创建分区表
[CLUSTERED BY (分桶字段) INTO N BUCKETS] -- 可选:创建分桶表
[ROW FORMAT row_format] -- 可选:指定分隔符/SerDe
[STORED AS file_format] -- 可选:指定存储格式(ORC/Parquet/TextFile)
AS SELECT 字段1, 字段2 FROM 源表 [WHERE 条件];
-- 关键说明:
-- 1. TEMPORARY:创建临时表(会话结束自动删除);
-- 2. PARTITIONED BY:CTAS 创建分区表需特殊处理(见下文示例);
-- 3. STORED AS:默认存储格式继承源表,也可手动指定(如 STORED AS ORC)。
实操示例
sql
-- 基于person表,创建person_new表(含id、name字段,仅保留id<5的数据)
CREATE TABLE person_new
COMMENT 'CTAS创建的新表'
STORED AS ORC -- 指定存储格式为ORC(比默认TextFile更高效)
AS SELECT id, name FROM person WHERE id < 5;
删除表
删除整张表(结构 + 数据全删)
sql
drop table [if exists] table_name [PURGE]
注意 :外部表执行 DROP 时,加 PURGE 才会删除 HDFS 文件(默认仅删元数据)。
查看表描述信息
sql
desc [extended|formatted] [db_name.]table_name
extended:
- 核心作用 :输出原始、未格式化的底层元数据,包含 Hive 内部存储的完整表信息,适合开发 / 运维人员排查问题。
- 典型场景 :
- 查看表的 SerDe 序列化类、输入输出格式、分区信息、存储位置等底层配置。
- 调试表的序列化 / 反序列化问题,比如分隔符、字段映射错误。
formatted:
- 核心作用 :输出结构化、易读的格式化信息,将元数据按逻辑分组展示,适合数据分析人员快速了解表结构。
- 典型场景 :
- 快速查看表的基本信息(类型、存储格式、位置)、字段详情、分区信息。
- 确认表的分区键、桶数、是否外部表等关键属性。
乱码解决方案
实操演示
如果person表在乱码解决前创建的,此时查看表描述还是乱码。需要解决乱码后,删除原来的person表重新创建。
sql
hive> desc formatted person;
OK
# col_name data_type comment
id int 唯一标识id
name string 名称
likes array<string> 爱好
address map<string,string> 地址
# Detailed Table Information
Database: default #数据库实例
OwnerType: USER #归属 root 用户
Owner: root
CreateTime: Thu Nov 11 13:16:11 CST 2021 # 创建时间
LastAccessTime: UNKNOWN
Retention: 0
Location: hdfs://mycluster/user/hive_remote/warehouse/person
#hdfs路径
Table Type: MANAGED_TABLE # 表类型: 管理表 通常称为内部
Table Parameters:
COLUMN_STATS_ACCURATE {\"BASIC_STATS\":\"true\",\"COLUMN_STATS\":
{\"address\":\"true\",\"id\":\"true\",\"likes\":\"true\",\"name\":\"true\"}}
bucketing_version 2
numFiles 0 #有几个文件
numRows 0 #有多少行
rawDataSize 0
totalSize 0 #多大
transient_lastDdlTime 1636607771
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat:
org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No # 未使用压缩
Num Buckets: -1 # 分桶数量
Bucket Columns: [] # 分桶的列
Sort Columns: [] # 排序列
Storage Desc Params:
collection.delim - # 数组元素与元素之间,map的kv对与kv对之间的分隔符
field.delim , # 列与列之间分隔符
line.delim \n# 记录与记录之间的分隔符
mapkey.delim : #map的key和value之间的分隔符。
serialization.format ,
Time taken: 0.268 seconds, Fetched: 38 row(s)
内部表与外部表
(1) Hive 内部表
sql
CREATE TABLE [IF NOT EXISTS] table_name
删除表时,元数据与数据都会被删除
Table Type: MANAGED_TABLE 内部表
创建表的时候,内部表直接存储在默认的hdfs路径(/user/hive_remote/warehouse)
(2) Hive 外部表
sql
CREATE EXTERNAL TABLE [IF NOT EXISTS] table_name LOCATION hdfs_path
删除外部表只删除metastore的元数据,不删除hdfs中的表数据
Table Type: EXTERNAL_TABLE external
创建表的时候,外部表需要自己指定路径
分区表
概述
必须在表定义时指定对应的partition字段,分区的本质相当于在表的目录下在分目录进行数据的存储。
分区好处:
查询时可以通过过滤不需要的分区下的数据,减少查询时的磁盘IO操作。
- 单分区建表语句:
sql
create table day_table (id int, content string) partitioned by (dt string);
单分区表,按天分区,在表结构中存在id,content,dt三列。
以dt为文件夹区分
2.双分区建表语句:
sql
create table day_hour_table (id int, content string) partitioned by (dt string,
hour string);
双分区表,按天和小时分区,在表结构中新增加了dt和hour两列。
先以dt为文件夹,再以hour子文件夹区分
理论上分区的个数可以任意多,但是常用的为单分区和双分区。
**注意:**定义分区和格式化语句的位置(在row format 上边)
分区字段不能出现在table后面的小括号中。
分区的元数据保存到mysql的hive_remote数据库实例的表中:PARTITION_KEYS、
PARTITION_KEY_VALS、PARTITIONS。
添加分区
表已创建,在此基础上添加分区,注意只能添加在表创建时定义好的分区的值
方式 1:静态添加分区(手动指定分区,适用于已有数据文件)
这是最常用的方式,用于给已有分区数据文件的目录「注册」分区元数据(Hive 识别分区的核心是元数据,而非仅 HDFS 文件)。
sql
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, ...)
实战示例
假设已有分区表 user_log(分区字段:dt(日期)、area(地区)),HDFS 上已有数据文件在 /user/hive/warehouse/user_log/dt=2026-01-19/area=east/ 目录下,需要手动添加该分区:
sql
-- 1. 先创建分区表(前提)
CREATE TABLE user_log (
id INT,
user_name STRING,
action STRING
)
PARTITIONED BY (dt STRING, area STRING) -- 定义分区字段
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
-- 2. 添加单个分区(指定存储路径),定义了多少个分区字段,添加时候就需要指定多少个值
ALTER TABLE user_log ADD PARTITION (dt='2026-01-19', area='east')
LOCATION '/user/hive/warehouse/user_log/dt=2026-01-19/area=east';
-- 3. 批量添加多个分区
ALTER TABLE user_log ADD
PARTITION (dt='2026-01-19', area='west')
PARTITION (dt='2026-01-20', area='north')
PARTITION (dt='2026-01-20', area='south');
方式 2:动态添加分区(插入数据时自动创建,适用于新增数据)
sql
-- 1. 开启动态分区(临时生效,仅当前会话)
SET hive.exec.dynamic.partition=true; -- 开启动态分区(默认关闭)
SET hive.exec.dynamic.partition.mode=nonstrict; -- 非严格模式(允许所有分区字段动态)
SET hive.exec.max.dynamic.partitions=1000; -- 最大动态分区数(根据需求调整)
-- 2. 插入数据并自动创建分区
INSERT INTO TABLE 表名 PARTITION (分区字段1, 分区字段2) -- 只写分区字段名,不写值
SELECT 字段1, 字段2, 分区字段1值, 分区字段2值 FROM 源表;
实战示例
向 user_log 表插入数据,自动按 dt 和 area 创建分区:
sql
-- 开启动态分区
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;
-- 从临时表导入数据,自动创建分区
INSERT INTO TABLE user_log PARTITION (dt, area)
SELECT id, user_name, action, dt, area FROM tmp_user_log;
-- 说明:查询结果的最后两列会自动匹配分区字段dt、area,Hive根据值创建对应分区
删除分区
sql
alter table table_name drop [if exists] partition partition_spec[, partition
partition_spec, ...]
[ignore protection] [purge];
多分区字段删除分区时,可以指定一个值也可以指定多个值,如果只指定一个值时将下级分区也一起删除。如果上级分区只有一个下级分区,当删除该下级分区的时候,上级分区也一并删除。
修复分区
解决「HDFS 已有分区目录,但 Hive 元数据中无该分区记录」的问题,Hive 识别分区的核心是元数据库(如 MySQL)中的分区记录,而非仅 HDFS 上的目录。以下场景会导致二者不一致,需要修复分区:
- 手动在 HDFS 创建了分区目录 (如
hdfs dfs -mkdir /user/hive/warehouse/user_log/dt=2026-01-20),但未通过ALTER TABLE ADD PARTITION注册元数据; - 通过第三方工具(如 Spark/Flink)向 Hive 表写入分区数据,但未同步更新 Hive 元数据;
- 误删元数据库中的分区记录,但 HDFS 上的分区数据仍存在。
sql
MSCK [REPAIR] TABLE table_name [ADD/DROP/SYNC PARTITIONS];
-- ADD:仅添加缺失的分区(默认行为)
-- DROP:删除元数据中有但HDFS无的分区
-- SYNC:同时执行ADD+DROP,保证元数据与HDFS完全一致
实操示例
假设 user_log 表的分区字段是 dt(日期),HDFS 上已手动创建 dt=2026-01-20 目录,但元数据中无该分区:
sql
-- 1. 先查看当前元数据中的分区(无2026-01-20)
SHOW PARTITIONS user_log;
-- 输出:dt=2026-01-19
-- 2. 修复分区(自动添加HDFS上的dt=2026-01-20分区)
MSCK REPAIR TABLE user_log;
-- 执行后会提示:Added partition to metastore user_log@dt=2026-01-20
-- 3. 再次查看分区(已包含2026-01-20)
SHOW PARTITIONS user_log;
-- 输出:dt=2026-01-19、dt=2026-01-20
-- 4. 进阶:同步分区(删除无效分区+添加缺失分区)
MSCK SYNC PARTITIONS user_log;
注意:
-
分区目录命名规范 :HDFS 上的分区目录必须严格遵循
分区字段名=值的格式(如dt=2026-01-20,而非2026-01-20),否则MSCK REPAIR无法识别;- 错误目录名:
/user/hive/warehouse/user_log/2026-01-20/→ 无法识别; - 正确目录名:
/user/hive/warehouse/user_log/dt=2026-01-20/→ 可识别。
- 错误目录名:
-
多分区字段的目录层级 :多分区字段(如
dt+area)的目录必须按「分区字段定义顺序」嵌套(dt=2026-01-20/area=north/),否则修复失败;
分桶表
分桶概述
分区提供一个通过目录隔离数据和查询优化的的遍历方式,不过不是所有的数据集都能形参合理的分区。对于一张表或这分区,可以进一步形参分桶,相比于分区分桶是个更小粒度的数据范围的划分。
分桶表是对列值取哈希值取模的方式,将不同数据放到不同文件中存储;由列的哈希值除以桶的个数得到的余数来决定每条数据划分在哪个桶中。
分区的本质是分目录 ,分桶的本质是分文件。
适用场景:
数据抽样( sampling )
关联查询

mr运行时会根据bucket的个数自动分配reduce task个数。(用户也可以通过mapred.reduce.tasks自己设置reduce任务个数,但分桶时不推荐使用)
注意:一次作业产生的桶数(文件数量)和reduce task个数一致。
创建分桶表
关键词:
sql
CREATE TABLE 表名 (
字段1 类型,
字段2 类型,
...
)
-- 可选:先分区,再分桶(分区+分桶是生产常用组合)
PARTITIONED BY (dt STRING)
-- 分桶核心配置
CLUSTERED BY (分桶字段)
-- 分桶数量
INTO N BUCKETS
-- 可选:桶内排序(提升查询效率)
SORTED BY (排序字段 ASC/DESC)
-- 存储格式(推荐 ORC/Parquet)
STORED AS ORC;
实战示例
开启分桶配置
bash
set hive.enforce.bucketing = true;
创建分桶表:
sql
create table psnbucket( id int, name string, age int) clustered by (age) into 4 buckets
row format delimited fields terminated by ',';
创建原始数据表:
sql
create table psn31( id int, name string, age int) row format delimited fields terminated by ',';
准备测试数据:
bash
[root@node4 data]# vim bucket
1,tom,11
2,cat,22
3,dog,33
4,hive,44
5,hbase,55
6,mr,66
7,alice,77
8,scala,88
将数据给添加到psn31表中:
bash
hive> load data local inpath '/root/data/bucket' into table psn31;
将psn31中的数据导入到psnbucket中(核心避坑:不能用 LOAD DATA,必须用 INSERT SELECT,分桶表的数据必须通过 INSERT SELECT 插入(Hive 会自动按哈希拆分数据),直接 LOAD DATA 会导致分桶失效),4个桶会产生四个reduce任务。
bash
hive> insert into table psnbucket select id,name,age from psn31;
查看文件列表:
bash
[root@node4 data]# hdfs dfs -ls /user/hive_remote/warehouse/psnbucket
Found 4 items
-rw-r--r-- 3 root supergroup 21 2026-01-21 17:12 /user/hive_remote/warehouse/psnbucket/000000_0
-rw-r--r-- 3 root supergroup 20 2026-01-21 17:12 /user/hive_remote/warehouse/psnbucket/000001_0
-rw-r--r-- 3 root supergroup 17 2026-01-21 17:12 /user/hive_remote/warehouse/psnbucket/000002_0
-rw-r--r-- 3 root supergroup 20 2026-01-21 17:12 /user/hive_remote/warehouse/psnbucket/000003_0
抽样查询分析
sql
select * from bucket_table tablesample(bucket x out of y on columns);
tablesample 语法:
tablesample(bucket x out of y on columns)
x:表示从哪个bucket开始抽取数据
y:必须为该表总bucket数的倍数或因子columns:分桶的列名
注意:x<=y,不能是x>y。
当表总 bucket 数为 32 时
- TABLESAMPLE(BUCKET 3 OUT OF 16 on columns),抽取哪些数据?
共抽取2(32/16)个bucket的数据,抽取第3、第19(3+16)个bucket的数据
- TABLESAMPLE(BUCKET 3 OUT OF 256 on columns),抽取哪些数据?共抽取1/8(32/256)个bucket的数据,抽取第3个bucket的1/8数据。
DML(数据操作语言)
添加数据(核心)
Load 数据(文件数据级别)
用于将文件数据加到数据表中
sql
load data [local] inpath 'filepath' [overwrite] into table tablename [partition
(partcol1=val1, partcol2=val2 ...)]
**local:**load的本地文件,将filepath指定的本地文件上传到hdfs指定的目录(对应表的目录)
无 **local:**filepath是hdfs上一个文件,将它移动到指定目录(对应表的目录)
**overwrite:**使用overwrite表示覆盖,没有它表示追加
实操演示:
准备工作
bash
[root@node4 ~]# mkdir data
[root@node4 ~]# cd data/
[root@node4 data]# vim person.txt
1,小明1,lol-book-movie,beijing:xisanqi-shanghai:pudong
2,小明2,lol-book-movie,beijing:xisanqi-shanghai:pudong
3,小明3,lol-book-movie,beijing:xisanqi-shanghai:pudong
4,小明4,lol-book-movie,beijing:xisanqi-shanghai:pudong
5,小明5,lol-movie,beijing:xisanqi-shanghai:pudong
6,小明6,lol-book-movie,beijing:xisanqi-shanghai:pudong
7,小明7,lol-book,beijing:xisanqi-shanghai:pudong
8,小明8,lol-book,beijing:xisanqi-shanghai:pudong
9,小明9,lol-book-movie,beijing:xisanqi-shanghai:pudong
本地文件 load 数据:
bash
hive> load data local inpath '/root/data/person.txt' into table person;
Loading data to table default.person
OK
Time taken: 6.155 seconds
hive> select * from person;
OK
1 小明1 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
2 小明2 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
3 小明3 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
4 小明4 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
5 小明5 ["lol","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
6 小明6 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
7 小明7 ["lol","book"] {"beijing":"xisanqi","shanghai":"pudong"}
8 小明8 ["lol","book"] {"beijing":"xisanqi","shanghai":"pudong"}
9 小明9 ["lol","book","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
Time taken: 3.611 seconds, Fetched: 9 row(s)
在hdfs文件系统上的对应目录/user/hive_remote/warehouse/person下多出一个person.txt文件。
hdfs 上的文件 load 数据:
首先将数据文件person.txt上传到hdfs的/ 目录下
bash
[root@node4 data]# ls
person.txt
[root@node4 data]# hdfs dfs -put person.txt /
使用load向person表中添加数据:
bash
hive> load data inpath '/person.txt' into table person;
检查hdfs上文件,得出:在hdfs文件系统中的/person.txt没有了,然后在hdfs文件系统中
的/user/hive_remote/warehouse/person目录下多出一个 person_copy_1.txt。就相当于将hdfs上的文
件从目录"/"下移动到/user/hive_remote/warehouse/person下(由于该目录下已经有一个名称为
person.txt的文件,所以移动过来的person.txt使用一个新的名称)。
insert(表数据导入)
用于将某个数据表中的某些(或全部)数据加到另外一个数据表中
sql
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;
**insert overwrite:**覆盖
**insert into:**追加
实操演示:
首先创建两张表person2_1和person2_2:
sql
create table person2_1(
id int comment "唯一标识id",
name string comment "名称"
)
row format delimited
fields terminated by ","
collection items terminated by "-"
map keys terminated by ":"
lines terminated by "\n";
create table person2_2(
id int comment "唯一标识id",
likes array<string> comment "爱好",
address map<string,string> comment "地址"
)
row format delimited
fields terminated by ","
collection items terminated by "-"
map keys terminated by ":"
lines terminated by "\n";
将表person中的数据分别放入到person2_1和person2_2中:
解决办法一:
sql
insert into table person2_1 select id,name from person;
insert into table person2_2 select id,likes,address from person;
如上解决版本会执行两次查询,效率较低。
解决办法二:
sql
from person2
insert into table person2_1 select id,name
insert into table person2_2 select id,likes,address;
删除表中数据
| 特性 | DELETE FROM table | TRUNCATE TABLE table |
| 核心作用 | 按条件删除表中的特定行数据 (支持 WHERE 子句) | 清空表的所有数据(不支持条件筛选) |
| 实现原理 | 基于 ACID 事务,在文件中标记删除记录,底层不会立即删除物理文件,而是通过合并小文件时清理标记的数据 | 直接删除表的底层数据文件(HDFS 上的文件),仅保留表结构 |
| 是否保留表结构 | 是 | 是 |
| 适用场景 | * 需要删除满足特定条件的行(如 DELETE FROM person WHERE id > 5) * 表开启了 ACID 事务(Hive 3.0+ 支持,需配置 transactional=true) * 对数据准确性要求高,且可以接受一定的性能开销 | * 需要快速清空整张表的所有数据 * 非分区表或分区表(分区表需加 PARTITION 子句清空指定分区,如TRUNCATE TABLE person PARTITION (dt='2026-01-19');) * 追求最高的删除效率,无需保留任何数据 |
| 关键限制 | * 仅支持事务表 (需在创建表时指定 TBLPROPERTIES ('transactional'='true')) * 仅支持 ORC 文件格式的表(默认格式 TextFile 不支持) * 性能较低,因为是逻辑删除,需要维护事务日志 * 不能用于外部表(External Table),否则会报错 |
* 不支持 WHERE 子句,无法按条件删除 * 可以用于内部表(Managed Table),但对外部表仅删除元数据,HDFS 上的物理文件不会被删除 * 分区表需指定 PARTITION (partition_col='value') 才能清空指定分区 * 执行速度极快,因为是直接删除文件,无事务日志开销 |
|---|
DQL(数据查询语言)
基本查询语句语法:
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 [offset,] rows]
可以发现HQL和SQL在DQL(Data Query Language)的语法上基本上差异不大,基础通用的语法在这里就不再赘述了,可以参考 MySQL基础-CSDN博客DQL部分的内容。本文讲解有差异的部分。
全局排序与分区排序
order by
全局排序,hql转换后的mr左右只有一个reduce任务。当数据量比较大时order by就要慎用,很有可能导致reduce需要较长的时间才能完成,或者完不成。
格式: order by 字段名 [asc|desc]
默认是asc 升序,desc表示降序
位置:
order by语句通常放置hql语句的最后。
sort by
sort by作用:在每一个reduce task任务内部排序,在大量数据集时使用order by存在着效率低下的问题,很多场景中并不需要全局排序。 每个reduce任务都会对应的结果文件part-r-xxxxxx,在每一个结果文件中都是有序的,全局是无序的。
通过set命令设置reduce任务的数量,有效期是直到下次修改该参数的值或hive连接关闭:
# set 参数=value; 设置参数的值
hive> set mapreduce.job.reduces=3;
# set 参数; 查看产生的值
hive> set mapreduce.job.reduces;
mapreduce.job.reduces=3
hive> select * from emp sort by deptno desc;
distribute by
distribute by:对应MR作业的partition(自定义分区),通常结合sort by一起使用。在某些情况下需要控制特定的行应该到哪个reduce任务中,为了后续的聚合操作。分区有对应reduce任务,有几个分区就有几个reduce任务;否则就看不到distribute by的效果。
distribute by分区规则是根据分区字段的hash值与分区数(reduce任务的总数)进行除模后,余数相同 的分到一个分区中。
要求:distribute by语句写在sort by语句的前面。
cluster by
当distribute by和sort by后面的字段相同时,可以使用cluster by进行简化。功能是等价的;但是只能使用升序排序,不能指定排序规则为asc或者desc。
实战- 基站掉话率分析
**需求:**找出掉话率最高的前10基站
创建原始数据表:
sql
create table jizhan(
record_time string,
imei int,
cell string,
ph_num int,
call_num int,
drop_num int,
duration int,
drop_rate double,
net_type string,
erl int)
row format delimited fields terminated by ',';
字段描述:
sql
record_time:通话时间
imei:基站编号
cell:手机编号
drop_num:掉话的秒数
duration:通话持续总秒数
创建结果表:
sql
create table jizhan_result(
imei string,
drop_num int,
duration int,
drop_rate double
);
数据文件准备:
将本文中的cdr_summ_imei_cell_info.csv上传到node4上/root/data目录下,然后vim该文件将第一行的表头数据双击dd删除,然后load到hive的jizhan表中。
sql
hive> load data local inpath '/root/data/cdr_summ_imei_cell_info.csv' into table
jizhan;
-- 查看数据
hive> select * from jizhan limit 10;
hive> select count(*) from jizhan;
976305
编写分析的sql语句,并将分析的结果写入到jizhan_result表中:
方式一:直接order全局排序
sql
from jizhan
insert into jizhan_result
select imei,sum(drop_num) sdrop,sum(duration) sdura,sum(drop_num)/sum(duration)
drop_rate
group by imei
order by drop_rate desc;
方式二:预处理数据,减少全局排序压力
如果数据量极大(比如亿级基站),直接用 ORDER BY 会让单个 Reduce 卡死,可先通过 DISTRIBUTE BY+SORT BY 筛选每个分区的前 100,再对这些 "分区前 100" 的结果做全局排序,最终筛选全局前 10:
sql
FROM (
SELECT
imei,sum(drop_num) sdrop,sum(duration) sdura,sum(drop_num)/sum(duration) drop_rate
FROM jizhan
GROUP BY imei
DISTRIBUTE BY imei
SORT BY drop_rate desc
LIMIT 100
) t
INSERT INTO jizhan_result
SELECT imei,sdrop,sdura,drop_rate
ORDER BY drop_rate desc
LIMIT 10;
查询结果表,获取前10条数据,也就掉话率最高的前10个基站:
sql
hive> select * from jizhan_result limit 10;
OK
639876 1 734 0.0013623978201634877
356436 1 1028 9.727626459143969E-4
351760 1 1232 8.116883116883117E-4
368883 1 1448 6.906077348066298E-4
358849 1 1469 6.807351940095302E-4
358231 1 1613 6.199628022318661E-4
863738 2 3343 5.982650314089142E-4
865011 1 1864 5.36480686695279E-4
862242 1 1913 5.227391531625719E-4
350301 2 3998 5.002501250625312E-4