在数据处理和分析的过程中,随着业务的发展和变化,我们可能需要对已有的 Hive 表进行调整、清理或修改表结构。为了确保操作的安全性,我们可以在进行这些操作之前先对 Hive 表进行备份。这样一来,即使在操作过程中发生了任何问题,我们也可以通过回退到备份数据来恢复之前的状态。

此外,在测试和开发环境中,我们经常需要使用真实的生产数据或者对数据进行一些实验性的操作。为了确保测试和开发工作不会对真实的生产数据造成影响,我们可以从 Hive 表中复制一份数据出来,创建一个安全的数据副本供测试和开发使用。从而可以在不影响真实生产数据的前提下进行各种实验和调试工作。

那么,如何快速备份或复制 Hive 表呢?本文将向大家介绍两种简单易行的复制 Hive 表的方法,以确保我们的数据始终处于安全可靠的状态。

方法一:使用 create table ... as ...

直接使用 create table ... as ... 复制表数据、表字段。语法如下:

1
2
3
create table if not exists 表名
as
select * from 要备份的表名

使用该方法虽然可以复制表的数据与字段,但表的属性会被修改。比如,如果要备份的表是分区表,那么使用该方法创建的表,分区字段将会变成普通字段,分区不存在。并且,该方法无法复制字段的 comment 备注信息。

下面的示例演示了如何使用该方法备份表。

首先,在 Hive 中创建分区表 test.dwd_user_info_snap_day:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE TABLE `test.dwd_user_info_snap_day`(
`user_id` int COMMENT '用户ID',
`nickname` string COMMENT '昵称',
`real_name` string COMMENT '真实姓名',
`create_time` string COMMENT '注册时间',
`country` string COMMENT '常驻国家',
`province` string COMMENT '常驻省份',
`city` string COMMENT '常驻城市'
)
COMMENT '用户快照表'
PARTITIONED BY (
`dt` string COMMENT '日期,格式yyyyMMdd')
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'

然后,模拟两条数据,写入表 test.dwd_user_info_snap_day 的 20230730 分区上:

1
2
3
4
5
6
7
8
with tmp as (
select 1466, 'ziyilon', 'Long Ziyi', '2018-06-05 21:47:30', 'United Kingdom', 'Liverpool', 'Liverpool'
union all
select 453, 'xiaoming8', 'Zhao Xiaoming', '2003-12-31 17:40:33', 'United Kingdom', 'Birmingham', 'Birmingham'
)

insert overwrite table `test.dwd_user_info_snap_day` partition(dt='20230730')
select * from tmp;

此时,查询该表的数据:

1
select * from `test.dwd_user_info_snap_day`

结果如下:

1
2
3
4
5
6
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| user_id | nickname | real_name | create_time | country | province | city | dt |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| 1466 | ziyilon | Long Ziyi | 2018-06-05 21:47:30 | United Kingdom | Liverpool | Liverpool | 20230730 |
| 453 | xiaoming8 | Zhao Xiaoming | 2003-12-31 17:40:33 | United Kingdom | Birmingham | Birmingham | 20230730 |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+

现在,使用 create table ... as ... 复制表数据、表字段,新的表名为 test.dwd_user_info_snap_day_bak:

1
2
3
create table if not exists test.dwd_user_info_snap_day_bak 
as
select * from test.dwd_user_info_snap_day;

查询表 test.dwd_user_info_snap_day_bak 数据:

1
select * from test.dwd_user_info_snap_day_bak;

结果如下:

1
2
3
4
5
6
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| user_id | nickname | real_name | create_time | country | province | city | dt |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| 1466 | ziyilon | Long Ziyi | 2018-06-05 21:47:30 | United Kingdom | Liverpool | Liverpool | 20230730 |
| 453 | xiaoming8 | Zhao Xiaoming | 2003-12-31 17:40:33 | United Kingdom | Birmingham | Birmingham | 20230730 |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+

查看表 test.dwd_user_info_snap_day_bak 的定义:

1
show create table test.dwd_user_info_snap_day_bak;

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CREATE TABLE `test.dwd_user_info_snap_day_bak`(
`user_id` int,
`nickname` string,
`real_name` string,
`create_time` string,
`country` string,
`province` string,
`city` string,
`dt` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://cluster/apps/hive/warehouse/test.db/dwd_user_info_snap_day_bak'
TBLPROPERTIES (
'COLUMN_STATS_ACCURATE'='{\"BASIC_STATS\":\"true\"}',
'numFiles'='2',
'numRows'='2',
'rawDataSize'='179',
'totalSize'='181',
'transient_lastDdlTime'='1692683800')

通过对比表 test.dwd_user_info_snap_day 的定义,我们可以发现该表的属性存在差异,并且字段的备注信息也已经丢失。

方法二:先创建表,再入插数据(推荐)

1) 先建表:

1
create table if not exists 新表名 like 旧表名;

2) 再插入数据:

1
insert into 新表名 select * from 旧表名

使用此方法可以复制表的数据与字段,但表的属性也会保持一致。

以前述的示例为例,创建新的表 test.dwd_user_info_snap_day_bak0822:

1
create table if not exists test.dwd_user_info_snap_day_bak0822 like test.dwd_user_info_snap_day;

插入数据:

1
2
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table test.dwd_user_info_snap_day_bak0822 partition(dt) select * from test.dwd_user_info_snap_day;

查询表 test.dwd_user_info_snap_day_bak0822 数据:

1
select * from test.dwd_user_info_snap_day_bak0822;

结果如下:

1
2
3
4
5
6
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| user_id | nickname | real_name | create_time | country | province | city | dt |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+
| 1466 | ziyilon | Long Ziyi | 2018-06-05 21:47:30 | United Kingdom | Liverpool | Liverpool | 20230730 |
| 453 | xiaoming8 | Zhao Xiaoming | 2003-12-31 17:40:33 | United Kingdom | Birmingham | Birmingham | 20230730 |
+---------+-----------+---------------+---------------------+----------------+------------+------------+----------+

查看表 test.dwd_user_info_snap_day_bak0822 的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE `test.dwd_user_info_snap_day_bak0822`(
`user_id` int COMMENT '用户ID',
`nickname` string COMMENT '昵称',
`real_name` string COMMENT '真实姓名',
`create_time` string COMMENT '注册时间',
`country` string COMMENT '常驻国家',
`province` string COMMENT '常驻省份',
`city` string COMMENT '常驻城市')
PARTITIONED BY (
`dt` string COMMENT '日期,格式yyyyMMdd')
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
'hdfs://cluster/apps/hive/warehouse/test.db/dwd_user_info_snap_day_bak0822'
TBLPROPERTIES (
'transient_lastDdlTime'='1692684821')

对比表 test.dwd_user_info_snap_day 的定义,我们可以发现表 test.dwd_user_info_snap_day_bak0822 的属性一致,而且字段的备注信息也没有丢失。

小结

本文介绍了两种简单易行的复制 Hive 表的方法,以确保数据的安全可靠性。

方法一:使用 create table … as …

该方法是直接使用 create table … as … 的语法来复制表数据和字段。但需要注意的是,该方法无法复制分区表的分区字段和字段的备注信息。

方法二:先创建表,再插入数据

这种方法先创建一个与原表结构相同的新表,然后通过 insert into … select * from … 的方式将数据插入新表中。与方法一不同的是,该方法可以完整地复制表的数据、字段以及属性,包括分区字段和字段的备注信息。在实际开发工作中,更推荐使用该方法复制表。

无论使用哪种方法,通过复制 Hive 表可以快速备份数据或创建安全的数据副本,以便进行调整、清理、修改表结构或在测试和开发环境中进行实验和调试工作,而不会对真实生产数据造成任何影响。

(END)