Hive 不同版本中update更新操作 (merge into 有则更新,无则插入)

本文介绍了Hive 2.2及以上版本中MergeInto语句的使用条件,包括参数配置、建表要求,并对比了与Hive 1.1.0版本Overwrite的不同之处。重点讲解了如何在ORC格式表上执行批量更新,以及如何优化更新效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、使用条件

hive2.2.0及之后的版本支持使用merge into 语法,使用源表数据批量目标表的数据。使用该功能还需做如下配置

1、参数配置
set hive.support.concurrency = true;
set hive.enforce.bucketing = true;
set hive.exec.dynamic.partition.mode = nonstrict;
set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
set hive.compactor.initiator.on = true;
set hive.compactor.worker.threads = 1;
set hive.auto.convert.join=false;
set hive.merge.cardinality.check=false; -- 目标表中出现重复匹配时要设置该参数才行
2、建表要求

Hive对使用Update功能的表有特定的语法要求, 语法要求如下:

(1)要执行Update的表中, 建表时必须带有buckets(分桶)属性

(2)要执行Update的表中, 需要指定格式,其余格式目前赞不支持, 如:parquet格式, 目前只支持ORCFileformat和AcidOutputFormat

(3)要执行Update的表中, 建表时必须指定参数(‘transactional’ = true);

DROP TABLE IF EXISTS dim_date_10000;
create table dim_date_10000(
 date_key        string                 comment'如:2018-08-08'
,day             int                  comment'日(1~31)'
,month           int                  comment'月,如:8'
,month_name      string        comment'月名称,如:8月'
,year            int                   comment'年,如:2018'
,year_month       int                   comment'年月,如201808'
,week_of_year    string                   comment'年内第几周 2018-1'
,week            int                  comment'周(1~7)'
,week_name       string          comment'周,如星期三'
,quarter         int                  comment'季(1~4)'
)
CLUSTERED BY (date_key) INTO 10 buckets
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS orc
TBLPROPERTIES('transactional'='true');
二、批量更新语法对比

对比在hive1.1.0 使用overwrite ,hive2.3.5使用merge into的方式 ,对不同量级的数据进行更新时的语法及效率。

之前hive表实现更新操作的步骤

insert overwrite table dim_date_100w
-- 旧的改变了的数据
select t2.date_key,t2.day,t2.month,t2.month_name,t2.year,t2.year_month,t2.week_of_year,t2.week,t2.week_name,1001 as quarter
from dim_date_100w t1
join dim_date_1w t2 on t1.date_key=t2.date_key
-- 旧的不变的数据
union all
select t1.*
from dim_date_100w t1
left join dim_date_1w t2 on t1.date_key=t2.date_key
where t2.date_key is null
-- 新增的数据
union all
select t1.*
from dim_date_1w t1
left join dim_date_100w t2 on t1.date_key=t2.date_key
where t2.date_key is null
;
Hive2.3.5
MERGE INTO dim_date_100w AS T USING dim_date_1w AS S
ON t.date_key=s.date_key
WHEN MATCHED THEN 
UPDATE SET quarter=1001   --关联上,变化的数据
WHEN NOT MATCHED THEN 
INSERT       --S 没关联上的 新增的数据
VALUES(S.date_key,S.day,S.month,S.month_name,S.year,S.year_month,S.week_of_year,S.week,S.week_name,S.quarter);
批量更新语法
 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>
<think>好的,我现在要解决用户的问题:如何在Hive中使用MERGE INTO实现跨分区的数据更新,并将数据写回到原始分区。首先,我需要回忆一下HiveMERGE INTO功能和相关知识。 用户提到了跨分区更新,并且需要数据回到原分区。根据之前的引用内容,MERGE INTO主要用于增量合并,支持ACID事务表,而INSERT OVERWRITE则是全量覆盖,适合分区替换。但用户希望的是跨分区更新,这可能涉及到不同分区之间的数据修改,并且结果要保留在原分区中。 首先,HiveMERGE INTO语句通常用于根据条件更新插入数据,类似于SQL中的MERGE操作。不过,Hive中的ACID表需要满足一些条件,比如表必须是分桶的,并且存储格式为ORC等。此外,动态分区的设置也可能影响操作,比如需要开启动态分区并设置为nonstrict模式(引用1和引用2中提到动态分区的模式设置)。 接下来,用户的问题涉及跨分区更新,也就是说,源表和目标表的分区可能不同,但需要根据某个条件更新目标表的数据,并且更新后的数据仍然保留在原分区。这时候需要考虑Hive是否允许在MERGE操作更新分区键的值。通常,更新分区键会导致数据移动到对应的分区目录中,但用户希望数据写回原分区,这可能存在矛盾。 根据引用4,MERGE INTO适合增量合并,而INSERT OVERWRITE适合全量覆盖。如果用户需要保持数据在原分区,可能需要确保在MERGE操作中不修改分区字段的值。否则,修改分区字段会导致Hive自动将数据移动到新的分区路径,这可能与用户的需求不符。 因此,解决方案可能包括以下步骤: 1. 确保目标表是ACID事务表,分桶且使用ORC格式。 2. 在MERGE语句中,使用ON条件匹配源表和目标表的键,但避免更新分区字段,只更新其他字段。 3. 如果必须更新分区字段,则需要接受数据会移动到新分区,这可能不符合用户要求,所以需要确认需求。 如果用户希望即使更新了分区字段,数据仍然保留在原分区,这实际上不可能,因为Hive的分区是基于分区字段的值来存储的。修改分区字段的值会自动触发数据存储到对应的分区路径。因此,用户可能需要重新考虑需求,或者在应用层处理数据,确保在更新时不修改分区字段。 另外,动态分区的设置(引用2)需要检查是否为nonstrict模式,否则在插入新分区时可能报错。同时,需要注意Hive版本是否支持MERGE INTO操作,因为该功能在较新的版本中才被引入。 可能的实现步骤: - 创建支持ACID的目标表,正确设置分桶和存储格式。 - 设置Hive的动态分区参数为nonstrict。 - 编写MERGE INTO语句,匹配源表和目标表的关键字段,当匹配时更新非分区字段,不匹配时插入新数据,但插入时分区字段可能来自源表,这样数据会根据源表的分区值存储到对应分区。 例如,假设目标表按dt分区,源表也有dt字段,MERGE操作可以根据源表的dt来决定插入到哪个分区,而更新操作不修改dt字段,从而保持原分区。 但用户提到“跨分区更新”,可能需要从其他分区读取数据来更新当前分区,这时候需要确保源表的数据与目标表的分区键正确关联,并且在ON条件中处理好关联关系,同时不修改目标表的分区键,这样数据就不会移动。 总结:关键点在于MERGE INTO时不修改分区字段,这样更新后的数据仍然保留在原分区。如果分区字段需要更改,则无法保留在原分区,必须移动到新分区。</think>在Hive中使用`MERGE INTO`实现跨分区更新并确保数据保留在原分区,需遵循以下步骤: --- ### 一、前置条件 1. **ACID事务支持** - 目标表必须是事务型表,创建时指定`TBLPROPERTIES ('transactional'='true')` - 存储格式需为ORC,且启用分桶(Bucketing) ```sql CREATE TABLE target_table ( id INT, value STRING, dt STRING -- 分区字段 ) PARTITIONED BY (dt) CLUSTERED BY (id) INTO 4 BUCKETS STORED AS ORC TBLPROPERTIES ('transactional'='true'); ``` 2. **配置动态分区** ```sql SET hive.exec.dynamic.partition=true; SET hive.exec.dynamic.partition.mode=nonstrict; -- 允许完全动态分区[^2] ``` --- ### 二、MERGE INTO语法实现 ```sql MERGE INTO target_table AS T USING source_table AS S ON T.id = S.id AND T.dt = S.dt -- 关键:分区字段必须包含在ON条件中 WHEN MATCHED THEN UPDATE SET value = S.value -- 仅更新非分区字段 WHEN NOT MATCHED THEN INSERT VALUES (S.id, S.value, S.dt); -- 插入时保留原分区值 ``` --- ### 三、关键逻辑说明 1. **分区字段处理** - **更新操作**:不可修改分区字段值,否则数据会迁移到新分区目录。因此`UPDATE`子句中仅允许修改非分区字段[^4]。 - **插入操作**:通过`INSERT`子句的`S.dt`动态解析分区,确保新数据按原分区规则存储。 2. **跨分区匹配** - 若需从其他分区更新数据(如`source_table`的分区与`target_table`不同),需在`USING`子句中明确关联条件,例如: ```sql ON T.id = S.id -- 允许跨分区匹配(如S.dt≠T.dt) ``` 但更新时仍需避免修改`T.dt`,否则数据会迁移至新分区。 --- ### 四、与分区更新的对比 | 场景 | 实现方式 | 特点 | |--------------------|---------------------|----------------------------------------------------------------------| | 原分区更新 | `MERGE INTO` | 精准更新非分区字段,数据保留原目录 | | 分区字段修改 | `INSERT OVERWRITE` | 需覆盖整个分区,无法实现部分更新 | --- ### 五、注意事项 1. **性能优化** - 对分桶字段(如`id`)进行`CLUSTER BY`,提升JOIN效率[^3]。 2. **数据一致性** - 测试时建议在非生产环境验证逻辑,避免误操作[^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值