Hive关联时丢失数据问题和常用的Hive SQL参数设置

简介: 针对结果的发生,本文从以下方面分析原因及提供解决方案:- 右表没有匹配的数据- 关联键数据类型不匹配- 受count列null值影响- Hive版本问题,在某些版本中,左连可能导致右表为null- 数据倾斜并在文末附属了`Hive SQL常用参数设置`的说明。
问题描述:
描述1:表A存在主键为1的数据行,表B也存在主键为1的数据行,表A left join 表B,取主键为1的数据行时,表B数据缺失。
描述2: 基于描述1,count(表B字段)数据时,计数行数不准确(主要表现为缺数据)

针对结果的发生,本文从以下方面分析原因及提供解决方案:

  • 右表没有匹配的数据
  • 关联键数据类型不匹配
  • 受count列null值影响
  • Hive版本问题,在某些版本中,左连可能导致右表为null
  • 数据倾斜

并在文末附属了Hive SQL常用参数设置的说明。

下面进行逐一分析

1. 右表没有匹配的数据

SQL基础,略。

2. 关联键数据类型不匹配

首先要确定一个问题,Hive会不会 自动匹配两表类型?下面开始验证

2.1 首先在test_db中创建表A,语句如下:

CREATE TABLE test_db.table_A
(
    id        int comment '编号',
    id_string string comment '编号字符串',
    name      string comment '名称'
)
    ROW FORMAT DELIMITED
        FIELDS TERMINATED BY ','
        LINES TERMINATED BY '\n'
        NULL DEFINED AS ''
    STORED AS TEXTFILE
    TBLPROPERTIES ("serialization.null.format" = '');

覆盖写入新数据如下:

insert overwrite table test_db.table_A
values (1, '1', '张三'),
       (2, '2', '李四'),
       (3, '3', '王五');
select id, id_string, name from test_db.table_A;

table_a数据.pngtable_a数据.png

2.2 首先在test_db中创建表B,语句如下:

CREATE TABLE test_db.table_B
(
    id        int comment '编号',
    id_string string comment '编号字符串',
    money     decimal(10, 2) comment '金钱'
)
    ROW FORMAT DELIMITED
        FIELDS TERMINATED BY ','
        LINES TERMINATED BY '\n'
        NULL DEFINED AS ''
    STORED AS TEXTFILE
    TBLPROPERTIES ("serialization.null.format" = '');

覆盖写入新数据如下:

insert overwrite table test_db.table_B
values (1, '1', 10.1),
       (2, '2', 20.1),
       (2, '2', 20.2),
       (3, '3', 30.1),
       (3, '3', 30.2),
       (3, '3', null);
select id, id_string, money from test_db.table_B;

table_b数据.pngtable_b数据.png

2.3 接下来使用int类型的table_a.id关联string类型的table_b.id_string

select a.id, b.id_string, a.name, b.money
from test_db.table_a a
left join test_db.table_b b on a.id = b.id_string

得到结果如下:
ab表关联.pngab表关联.png

可见,Hive不会因类型而关联异常。一般来讲,同一个含义的列在不同表中应保持列名和类型相同。

3. 受count列null值影响

在Hive Sql中,count()方法的使用及相关区别如下:

select count(*) from test_db.table_b;
-- 输出结果:6
select count(1) from test_db.table_b;
-- 输出结果:6
select count(money) from test_db.table_b;
-- 输出结果:5
select count(distinct money) from test_db.table_b;
-- 输出结果:5
select count(distinct coalesce(money, 1)) from test_db.table_b;
-- 输出结果:6

可见,count(column)将自动排除null值数据行

4. Hive版本问题,在某些版本中,左连可能导致右表为null

这里直接照搬文档如下:

在Hive 0.13.0和Hive 0.14.0版本中,这两个版本的Hive引擎使用了新的Cost-Based Optimizer(CBO)作为查询优化器。
CBO主要是通过对数据分布和数据统计信息进行分析,来选择最优的查询计划。
但是,在左连接的情况下,CBO对于一些特殊情况下的数据分布和统计信息计算出的结果可能存在误差,从而导致左连接时未能正确关联上数据。

从Hive 0.15.0版本开始,Hive引擎将默认使用新的Rule-Based Optimizer(RBO),而不再使用CBO,因此该问题已经得到了解决。
同时,在Hive 0.13.0和0.14.0版本中,可以通过设置hive.cbo.enable参数为false,禁用CBO,从而规避这个问题。

5. 数据倾斜

关联中的数据倾斜通常是由于大小表关联,可能某个Reducer处理数据量与其他差异过大导致
我们可以通过查询前临时设置来解决这个问题,下面介绍几个常用设置:

  • set hive.merge.smallfiles.avgsize=[数值];: 这个指令参数用于指定需要合并的小文件的平均大小,单位是字节。

默认值是 16 MB。当输入数据被分割成多个小文件时,如果这些小文件总大小超过了这个阈值,Hive会自动合并这些小文件。
这样可以减少Mapper的数量,提高作业的并发度,从而更好地处理数据倾斜的情况。

  • set hive.exec.reducers.bytes.per.reducer=[数值];: 这个参数用于指定每个 Reducer 处理的数据量大小,单位是字节。

这个数值过大、过小都不合适,需要预估查询从而设置更合适的范围。
并且,如果发生了本文中提到的关联丢失数据,我建议仅使用这条参数即可解决,根据查询大小,尝试增加或减少此数值,尽可能平衡每个reducer的处理即可!

  • set mapred.max.split.size=[数值]:这个参数用于指定 Map 任务处理的输入数据的最大分片大小,单位是字节,默认值是 1GB。

默认值是 64MB。如果该参数设置得太小,可能会导致数据分片过多,从而增加了任务调度的开销,降低了并发度,也可能造成数据倾斜。
如果设置得太大,又会导致单个 Map 任务处理的数据量过大,从而增加了单个任务的执行时间。因此,需要根据实际情况进行调整,使 Map 任务处理的数据量适中,以达到最佳的性能。

总结

几个方面分析完成以后,可以发现基本是数据倾斜导致的关联数据缺失,我建议参考上方所说的在执行特殊查询前加上set hive.exec.reducers.bytes.per.reducer=[数值];
尝试解决。需注意的是,请查看原本该值设定是多少,然后根据你的查询去决定数值为多少

附文:常用的Hive SQL参数设置及解释

  1. set hive.exec.parallel=true;: 默认值为false,开启Hive执行任务的并行化,这样Hive可以在多个处理器上同时执行不同的任务,提高作业的执行速度。
  2. set mapreduce.job.queuename=hadoop;: 默认值为"default",指定MapReduce作业提交到的队列名称,当Hadoop集群中有多个队列时,可以通过此参数指定作业提交的队列。
  3. set hive.exec.dynamic.partition=true;: 默认值为false,开启Hive动态分区功能,这样可以在插入数据时动态创建分区,而不是需要提前手动创建好分区。
  4. set hive.exec.dynamic.partition.mode=nostrict;: 默认值为"strict",设置动态分区模式为非严格模式,即在插入数据时,只需要指定要插入的分区字段即可,不需要指定所有的分区字段。
  5. set hive.exec.max.dynamic.partitions=10000;: 默认值为1000,设置动态分区最大数量为10000个,即在动态分区时,最多只能创建10000个分区。
  6. SET hive.exec.max.dynamic.partitions.pernode=10000;: 默认值为100,设置每个节点上动态分区最大数量为10000个,即每个节点最多只能创建10000个分区。
  7. set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;: 默认值为null,设置Map任务输出时采用Gzip压缩算法进行压缩,减小数据的磁盘占用。
  8. set hive.exec.compress.intermediate=true;: 默认值为false,开启Hive中间结果的压缩,可以减小数据在磁盘上的占用。
  9. set mapred.output.compression.type=BLOCK;: 默认值为NONE,可选的值为NONE、BLOCK、RECORD。设置输出数据的压缩格式为块压缩(Block Compression),这种压缩方式可以提高压缩率。
  10. set hive.exec.compress.output=true;: 默认值为false,开启输出结果的压缩,减小数据在磁盘上的占用。
  11. set hive.merge.smallfiles.avgsize=120000000;: 默认值为256MB,当小文件个数超过一定阈值时,Hive会自动将它们合并成一个大文件。这里设置合并后的文件大小为120MB。
  12. set hive.exec.reducers.bytes.per.reducer=10000000;: 默认值为1GB,设置每个Reducer处理的数据量大小,这里设置为10MB。
  13. set mapred.max.split.size=100000000;: 默认值为64MB,设置每个输入Split的最大大小为100MB,这样可以控制每个Map任务处理的数据量,避免数据倾斜。
  14. set hive.merge.mapfiles=true;: 默认值为false,开启小文件合并,将多个小文件合并成一个大文件。
  15. set hive.merge.mapredfiles=true;: 默认值为false,开启Map任务输出结果的小文件合并功能,可以将多个Map任务输出的小文件合并成一个大文件。
相关文章
|
5天前
|
SQL 存储 Oracle
Oracle的PL/SQL定义变量和常量:数据的稳定与灵动
【4月更文挑战第19天】在Oracle PL/SQL中,变量和常量扮演着数据存储的关键角色。变量是可变的“魔术盒”,用于存储程序运行时的动态数据,通过`DECLARE`定义,可在循环和条件判断中体现其灵活性。常量则是不可变的“固定牌”,一旦设定值便保持不变,用`CONSTANT`声明,提供程序稳定性和易维护性。通过 `%TYPE`、`NOT NULL`等特性,可以更高效地管理和控制变量与常量,提升代码质量。善用两者,能优化PL/SQL程序的结构和性能。
|
24天前
|
SQL 存储 关系型数据库
一文搞懂SQL优化——如何高效添加数据
**SQL优化关键点:** 1. **批量插入**提高效率,一次性建议不超过500条。 2. **手动事务**减少开销,多条插入语句用一个事务。 3. **主键顺序插入**避免页分裂,提升性能。 4. **使用`LOAD DATA INFILE`**大批量导入快速。 5. **避免主键乱序**,减少不必要的磁盘操作。 6. **选择合适主键类型**,避免UUID或长主键导致的性能问题。 7. **避免主键修改**,保持索引稳定。 这些技巧能优化数据库操作,提升系统性能。
219 4
一文搞懂SQL优化——如何高效添加数据
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
5天前
|
SQL Oracle 安全
Oracle的PL/SQL循环语句:数据的“旋转木马”与“无限之旅”
【4月更文挑战第19天】Oracle PL/SQL中的循环语句(LOOP、EXIT WHEN、FOR、WHILE)是处理数据的关键工具,用于批量操作、报表生成和复杂业务逻辑。LOOP提供无限循环,可通过EXIT WHEN设定退出条件;FOR循环适用于固定次数迭代,WHILE循环基于条件判断执行。有效使用循环能提高效率,但需注意避免无限循环和优化大数据处理性能。掌握循环语句,将使数据处理更加高效和便捷。
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL条件控制:数据的“红绿灯”与“分岔路”
【4月更文挑战第19天】在Oracle PL/SQL中,IF语句与CASE语句扮演着数据流程控制的关键角色。IF语句如红绿灯,依据条件决定程序执行路径;ELSE和ELSIF提供多分支逻辑。CASE语句则是分岔路,按表达式值选择执行路径。这些条件控制语句在数据验证、错误处理和业务逻辑中不可或缺,通过巧妙运用能实现高效程序逻辑,保障数据正确流转,支持企业业务发展。理解并熟练掌握这些语句的使用是成为合格数据管理员的重要一环。
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL表达式:数据的魔法公式
【4月更文挑战第19天】探索Oracle PL/SQL表达式,体验数据的魔法公式。表达式结合常量、变量、运算符和函数,用于数据运算与转换。算术运算符处理数值计算,比较运算符执行数据比较,内置函数如TO_CHAR、ROUND和SUBSTR提供多样化操作。条件表达式如CASE和NULLIF实现灵活逻辑判断。广泛应用于SQL查询和PL/SQL程序,助你驾驭数据,揭示其背后的规律与秘密,成为数据魔法师。
|
27天前
|
SQL 关系型数据库 MySQL
SQL INSERT INTO order_record SELECT * FROM 从一张表查出数据插入到另一张表
SQL INSERT INTO order_record SELECT * FROM 从一张表查出数据插入到另一张表
14 0
|
1月前
|
SQL 数据可视化 Apache
阿里云数据库内核 Apache Doris 兼容 Presto、Trino、ClickHouse、Hive 等近十种 SQL 方言,助力业务平滑迁移
阿里云数据库 SelectDB 内核 Doris 的 SQL 方言转换工具, Doris SQL Convertor 致力于提供高效、稳定的 SQL 迁移解决方案,满足用户多样化的业务需求。兼容 Presto、Trino、ClickHouse、Hive 等近十种 SQL 方言,助力业务平滑迁移。
阿里云数据库内核 Apache Doris 兼容 Presto、Trino、ClickHouse、Hive 等近十种 SQL 方言,助力业务平滑迁移
|
1月前
|
SQL 安全 数据库
第三章用sql语句操作数据
第三章用sql语句操作数据
10 0
|
1月前
|
SQL 数据库 索引
解决SQL报错:索引中丢失IN或OUT參数
解决SQL报错:索引中丢失IN或OUT參数