Hive多分区表重命名失败问题分析

    项目上有一张Hive分区表,分区数非常多,大约有2000+个分区,然后需要增加一个字段,然后华丽丽的发现,执行了半小时之后,失败了…然后想着那就对表进行重命名吧,使用新表来替换这张旧表,旧表使用别的名字,然后又是漫长半小时等待,又失败了…表重命名操作不就是修改下元数据么?!为啥还会失败,带着这个问题,来探究下Hive表重命名相关的原理。

    “参考一”和“参考二”也遇到了类似的问题,一个是数据库连接的超时时间设置的太短,另一个是数据库关键字段未建索引,这些原因和本人项目中发生的情况有所不同,我们的项目没有上述的问题,同时Hive版本使用的是1.2.X。所以还是通过源码去了解下Rename的时候到底是做了啥导致程序执行的这么慢吧

Hive分区表重命名源码解析:

     表重命名相关的源码在HiveAlterHandler.java文件中,应该说Alter table的相关操作都在这个文件中。Hive表的重命名会涉及到MySQL中元数据信息的修改以及可能会移动HDFS上的文件路径。下文的源码分析只会涉及Hive分区表的重命名操作,其他暂且先不管。

    我们从alterTable()方法看进去。首先是一些参数的校验,这个没啥好说的。接着就是执行msdb.openTransaction()开启事务 ,准备修改元数据信息了。源码中有这么一段注释:

// if this alter is a rename, the table is not a virtual view, the user
// didn't change the default location (or new location is empty), and
// table is not an external table, that means user is asking metastore to
// move data to the new location corresponding to the new name

   即对于virtual view或者外部表是不能修改表名的,也就是说只有内部表才可以修改表名。
   同时如果创建表的时候使用的是默认路径(即没有显示指定location),那么HDFS数据目录也会移动到新表的目录下。

    所以接下来就是移动HDFS数据同时修改分区的元数据信息,如果创建表时使用的是默认路径的话:

// that means user is asking metastore to move data to new location
// corresponding to the new name
// get new location
Database db = msdb.getDatabase(newt.getDbName());
Path databasePath = constructRenamedPath(wh.getDatabasePath(db), srcPath);
destPath = new Path(databasePath, newt.getTableName().toLowerCase());
destFs = wh.getFs(destPath);

newt.getSd().setLocation(destPath.toString());
moveData = true;
...// HDFS移动下文件目录,这一步应该挺快的

    接下来就是元数据信息修改了,主要是如下两步操作:

// 1. 查询分区信息,删除每个分区的列统计信息,修改分区元数据信息
List<Partition> parts = msdb.getPartitions(dbname, name, -1);
for (Partition part : parts) {
    //existing partition column stats is no longer valid, remove them
    msdb.deletePartitionColumnStatistics(dbname, name, oldPartName, part.getValues(), null);
    msdb.alterPartition(dbname, name, part.getValues(), part);
}
// 2. 修改分区的列统计信息
updateTableColumnStatsForAlterTable(msdb, oldt, newt);

    其中deletePartitionColumnStatistics()方法会查询出列统计信息,然后删除:

mStatsObjColl= (List<MPartitionColumnStatistics>)query.execute(partName.trim(),
    HiveStringUtils.normalizeIdentifier(dbName),
    HiveStringUtils.normalizeIdentifier(tableName));
pm.retrieveAll(mStatsObjColl);

if (mStatsObjColl != null) {
  pm.deletePersistentAll(mStatsObjColl);
} else {
  throw new NoSuchObjectException("Column stats doesn't exist for db=" + dbName +
    " table=" + tableName + " partition" + partName);
}

   hive.stats.column.autogather设置为true时,表示开启了Hive的列统计信息。每个分区每一列都会生成一条记录,列统计信息在元数据库表中记录如下所示:

《Hive多分区表重命名失败问题分析》

     所以分区数和列数越多,列统计信息就越多,2000+的分区,列数有100+列,这张表中记录条数就达到20W+。而且删除的时候是逐个分区删除的,速度更慢,咨询了下平台组的小伙伴以及网上的资料,大致确定慢是慢在这里。

    后续的解决方案是,建一张新表,把数据写入到新表中。旧表中的数据通过ETL的方式迁移到新表中。

参考:

        增加Hive表字段超时_MapReduce服务 MRS_故障排除_使用Hive_华为云

        Hive表列属性更新慢并偶尔更新失败 · Big Data Knowledge Base

        hive – 随笔分类 – 松伯 – 博客园

        元数据管理-hive表Statistics信息获取_songjifei的专栏-CSDN博客_hive元数据管理

    原文作者:淡定一生2333
    原文地址: https://blog.csdn.net/zc19921215/article/details/120660910
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞