1、问题
如何删除Hive分区名有特殊字符的分区?
2、背景
最近在做数据治理工作,在Hive的元数据库里瞎逛的时候发现了一个奇怪的分区 dt=%7Bdt}
,发现几个问题:
- hdfs有数据,但是无法使用SQL的where条件查询分区数据,使用转义也失效
- 无法使用
analyze table
统计分区信息 count
全表会计算数据,但是又无法过滤查询,可能对数据统计造成影响
考虑到分区无法使用,还可能对数据统计造成干扰,于是想要对分区进行删除。然后问题来了,使用了
ALTER TABLE db_name.table_name drop partition (dt='%7Bdt}')
无法删除
3、解决方案
3.1、 我们取正常的一天数据和有问题的分区名进行比较
正常 | 问题 |
---|---|
dt=20190429 | dt=%7Bdt} |
发现还是有一定的规律,正常情况下的日期字段居然变成了 %7Bdt}
,看起来像是没有赋值的 {dt}
字符 {
变成了 %7B
,经过查找确认,%7B
是 {
的URL编码
3.2、 网上冲浪找解决办法
在网上找到一篇类似的文章[1]
hive sql脚本中带变量如:select table_coulm from table_name where dt=’{etl_date}’; —dt是分区名 如果变量未赋值,{etl_date}会变成特殊字符dt=$%7Betl_date} 删除带特殊字符的分区:alter table tmp_h02_click_log drop partition(dt=’${etl_date}’); 直接删除原有的变量名不要带转义字符。 hive 处理字段是忘记起别名 hive会默认生成一个列名如:_c1 查询_c1 必须用反向引号括起来
_c1
按照博主的意思,是没有对变量赋值, {dt}
以某种不可知(未读源码)的方式变成了 %7Bdt}
3.3、 尝试使用以下删除语句对分区进行阐述
ALTER TABLE db_name.table_name drop partition(dt='{dt}');
终端输出如下
ls: cannot access /usr/local/xyhadoop/spark/lib/spark-assembly-*.jar: No such file or directory
Logging initialized using configuration in file:/usr/local/xyhadoop/apache-hive-1.2.2-bin/conf/hive-log4j.properties
Dropped the partition dt=%7Bdt}
OK
Time taken: 2.371 seconds
从打印出来的日志里观察可以发现,确实是 {dt}
变成了 %7Bdt}
,我们用 {dt}
作为分区名称仍然可以成功删除。检查数据库,分区成功删除,该方法确实有效。
3.4、复现验证
我尝试使用下面的SQL进行插入数据,能复现博客中作者说的情况。
insert overwrite table db_name.table_name partition(dt='{dt}')
然后使用下面SQL进行删除数据
ALTER TABLE db_name.table_name drop partition(dt='{dt}');
3.5、其他解决方案
在网上找解决问题的方案时,很多人都是直接删除HDFS文件,之后再删除hive元数据。如https://blog.csdn.net/fg654748861/article/details/46123887这篇文章所示。
尽管这能很简单的解决问题,但是不是很建议这样用,原因有以下几点
- 1、元数据库的del权限很高且危险,一般情况下开发人员不应该有该权限
- 2、需要依次删除所有相关的
PARTITIONS
、PARTITION_PARAMS
等数据表里的相关数据
总的来说操作风险较高
4、总结
- 使用
ALTER TABLE db_name.table_name drop partition(dt='{dt}')
能删除分区 %7B
是{
的URL编码表- 其他的字符有可能出现在Hive元数据中,如果分区名称是
%23dt%23
,原字符是#dt#
,#
的 URL编码是%23
- 猜想可能是SQL执行过程中经过了一次HTTP传输,将为负值的特殊符号转成了URL编码
5、参考
[1] forever_ai.hive删除分区名带特殊字符.CSDN:博客,2014-03-03
[2] 百度.URL编码表.百度百科:词条