记录一次HDP3.0 的hive 3.1.2由于未关闭ACID功能,导致使用到用户画像的Spark计算引擎报错,无法处理数据,impala无法查询的问题。由于hive 3.0之后默认开启ACID功能,默认建表都是使用ACID的事务表。而spark目前还不支持hive的ACID功能,因此无法读取ACID表的数据。
另外,读取不报错,但是读取不到数据的表INPUTFORMAT=org.apache.hadoop.hive.ql.io.orc.OrcInputFormat;报错insert-only 的表 INPUTFORMAT = org.apache.hadoop.mapred.TextInputFormat 。
在hdp3.1.5中hive3中内部表默认开启了ACID,当spark和impala创建和读取内部表的时候会报错,网上建议的方式是舍弃掉acid特性。
hive.strict.managed.tables=false
hive.create.as.insert.only=false
metastore.create.as.acid=false
对应hdp的hive默认配置做如下修改,重启hive服务后确实可以生效:
由于HDFS只支持文件的添加和删除,不支持修改,因此Hive原生并不支持原子性的行级别修改。
Hive中支持的表类型和ACID特性如下图所示:
表类型 | ACID | 文件格式 | 插入 | 更新/删除 |
---|---|---|---|---|
托管表:CRUD事务 | 是 | ORC | 是 | 是 |
托管表:仅插入式事务 | 是 | 任意格式 | 是 | 没有 |
托管表:临时 | 没有 | 任意格式 | 是 | 没有 |
外部表 | 没有 | 任意格式 | 是 | 没有 |
其中托管表是Hive内部表。
查看表的属性,指令:desc formatted tb_name
非ACID表:
| Table Type: | MANAGED_TABLE | NULL |
| Table Parameters: | NULL | NULL |
| | COLUMN_STATS_ACCURATE | {\"BASIC_STATS\":\"true\"} |
| | numFiles | 36554 |
| | numPartitions | 4582 |
| | numRows | 656353471 |
| | rawDataSize | 3687190343914 |
| | totalSize | 191558565757 |
| | transient_lastDdlTime | 1626229162 |
ACID表:
| Table Type: | MANAGED_TABLE | NULL |
| Table Parameters: | NULL | NULL |
| | bucketing_version | 2 |
| | comment | 交易日志表 |
| | numFiles | 2131 |
| | numPartitions | 2131 |
| | numRows | 1303371497 |
| | rawDataSize | 0 |
| | totalSize | 669842162666 |
| | transactional | true |
| | transactional_properties | insert_only |
| | transient_lastDdlTime | 1613705157 |
其中:
对于数仓中的行级数据更新删除需求比较频繁的,可以考虑使用事务表。
但平常的hive表并不建议使用事务表。因为事务表的限制很多,加上由于hive表的特性,也很难满足高并发的场景。
另外,如果事务表太多,并且存在大量的更新操作,metastore后台启动的合并线程会定期的提交MapReduce Job,也会一定程度上增重集群的负担。
结论: 除非有非常迫切的行级更新需求,又只能用hive表来做,才需要去考虑事务表。
注意事项
HDFS本身是不支持直接修改文件的,也不能保证有人追加内容时的读一致性。
因此,为了支持ACID的特性,Hive只能使用其他数据仓库常用的方法,也就是增量的形式记录更新和删除(也称做读时更新)。
存储在事务表中的数据会被分成两种类型的文件:
base文件,用来存放平常的数据
delta文件,用来存储新增、更新、删除的数据。每一个事务处理数据的结果都会单独新建一个delta文件夹用来存储数据。
在有用户要读取这个表的数据时,就会将base文件和delta文件都读取到内存,然后进行合并(就是判断哪些记录有被修改,哪些记录被删除等)。
ACID表的文件结构:${Hive_path}/db/table_name/base_{id}/file。
Found 2 items |
| -rw-rw----+ 3 hdfs hadoop 1091048351 2021-07-13 15:00 /warehouse/tablespace/managed/hive/db_name.db/tb_name/date=2021-06-30/base_0002252/000000_0
| -rw-rw----+ 3 hdfs hadoop 1091048351 2021-07-13 15:00 /warehouse/tablespace/managed/hive/db_name.db/tb_name/date=2021-06-30/delta_0000023_0000023_0000/000000_0
其中0000023
标识事务ID,0000表示序号,从上面的表中我们可以看到有一个事务的数据还未合并成base。
非ACID表,通过别的表格导入数据,文件目录为:
+----------------------------------------------------+
| DFS Output |
+----------------------------------------------------+
| 2.6 M 7.9 M /warehouse/tablespace/managed/hive/db_name.db/tb_name/day=2021-07-18/-ext-10000/000000_0 |
+----------------------------------------------------+
普通内部表文件目录:
+----------------------------------------------------+
| DFS Output |
+----------------------------------------------------+
| 7.4 M 22.1 M /warehouse/tablespace/managed/hive/db_name.db/tb_name/day=2021-07-18/000000_0 |
+----------------------------------------------------+
参考博客
Hive ACID和事务表支持详解_u013332124的专栏-CSDN博客
Hive ACID 增删改查 原理以及场景描述_Lara1111的博客-CSDN博客
Hive 官方手册翻译 – Hive Transactions (Hive 事务) - 范振勇 - 博客园 (cnblogs.com)
Spark 无法读取hive 3.x的表数据_u013024563的博客-CSDN博客
那么如果项目一开始就没有关闭hive的ACID设置,怎么解决这个问题呢?
思路:先关闭ACID设置
使用shell脚本或者java程序连接jdbc,导出已有库的所有表的建表语句,
只保留create table 原表名_bak(col1 type,col2 type,...)partition by (分区字段)store as ORC;
执行建表语句,新建表名,然后将数据从老表中查询出来,覆写到新表中。
然后旧表更名为 table名_old,新表面更名为原表名,这样就不影响到下游的使用。
更名操作命令:
当前Hive版本:3.1.3000.7.1.7.0-551
创建hive外部表: CREATE TABLE IF NOT EXISTS `alter_test` (a string,b string) STORED AS ORC TBLPROPERTIES("transactional"="false");
转hive内部表:ALTER TABLE alter_test SET TBLPROPERTIES('external'='false');
重命名:ALTER TABLE alter_test RENAME TO alter_test_bak;
设置hive表的Location的hdfs路径:
ALTER TABLE RENAME TO ;
ALTER TABLE set location "hdfs://";
如果在编写shell脚本时候导出的建表语句有格式化输出可以使用beeline如下命令:
如果创建的表impala还是无法查询到数据,记得可能是impala的元数据没有及时更新。可执行如下命令刷新元数据:
invalidate metadata 全量刷新,性能消耗较大,主要用于 hive 当中新建数据库或者数据库表的时候来进行刷新。
refresh dbname.tablename 增量刷新,刷新某一张表的元数据,主要用于刷新 hive 当中数据表里面的数据改变的情况。
quit/exit 命令 从 Impala shell 中弹出
explain 命令 用于查看 sql 语句的执行计划
使用root用户执行hive -f /home/insert.sql报错
解决办法:
进入 Ambari,
进入HDFS,
点击Configs
打开 Advanced hdfs-site,设置dfs.permissions.enabled=false.
重启HDFS,以及相关组建。
上一篇:Mysql注入
下一篇:[数据结构初阶]顺序表