乐趣区

关于hive:Hive事务

1、Hive 事务外围流程

1.1、时序图

1.2、外围流程图

2、Hive 事务 HDFS 文件存储分析

2.1、表构造

前提是设置 set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
应用 DbTxnManager Db 事务管理器

CREATE TABLE employee (id int, name string, salary int)
STORED AS ORC TBLPROPERTIES ('transactional' = 'true');

2.2、插入数据解析

INSERT INTO employee VALUES
(1, 'Jerry', 5000),
(2, 'Tom',   8000),
(3, 'Kate',  6000);

INSERT 语句会在一个事务中运行。它会创立名为 delta 的目录,寄存事务的信息和表的数据

/user/hive/warehouse/employee/delta_0000001_0000001_0000
/user/hive/warehouse/employee/delta_0000001_0000001_0000/_orc_acid_version
/user/hive/warehouse/employee/delta_0000001_0000001_0000/bucket_00000

目录名称的格局为delta_minWID_maxWID_stmtID,即 delta 前缀、写事务的 ID 范畴、以及语句 ID。具体来说:

  • 所有 INSERT 语句都会创立 delta 目录。UPDATE 语句也会创立 delta 目录,但会先创立一个 delete 目录,即先删除、后插入。delete 目录的前缀是 delete_delta
  • Hive 会为所有的事务生成一个全局惟一的 ID,包含读操作和写操作。针对写事务(INSERT、DELETE 等),Hive 还会创立一个写事务 ID(Write ID),该 ID 在表范畴内惟一。写事务 ID 会编码到 delta 和 delete 目录的名称中
  • 语句 ID(Statement ID)则是当一个事务中有多条写入语句时应用的,用作惟一标识。(MERGE 语句可能会生成多个 Statement ID)

再看文件内容,_orc_acid_version 的内容是 2,即以后 ACID 版本号是 2。它和版本 1 的次要区别是 UPDATE 语句采纳了 split-update 个性,即上文提到的先删除、后插入。这个个性可能使 ACID 表反对条件下推等性能,具体能够查看 HIVE-14035。bucket_00000 文件则是写入的数据内容。因为这张表没有分区和分桶,所以只有这一个文件。事务表都以 ORC 格局存储的,咱们能够应用 hive 自带工具 来查看文件的内容:

hive --orcfiledump -d /user/hive/warehouse/employee/delta_0000001_0000001_0000

{"operation":0,"originalTransaction":1,"bucket":536870912,"rowId":0,"currentTransaction":1,"row":{"id":1,"name":"Jerry","salary":5000}}
{"operation":0,"originalTransaction":1,"bucket":536870912,"rowId":1,"currentTransaction":1,"row":{"id":2,"name":"Tom","salary":8000}}
{"operation":0,"originalTransaction":1,"bucket":536870912,"rowId":2,"currentTransaction":1,"row":{"id":3,"name":"Kate","salary":6000}}

输入内容被格式化为了一行行的 JSON 字符串,咱们能够看到具体数据是在 row 这个键中的,其它键则是 Hive 用来实现事务个性所应用的,具体含意为:

  • operation : 0 示意插入,1 示意更新,2 示意删除。因为应用了 split-update,UPDATE 是不会呈现的
  • originalTransaction : 是该条记录的原始写事务 ID。对于 INSERT 操作,该值和 currentTransaction 是统一的。对于 DELETE,则是该条记录第一次插入时的写事务 ID
  • bucket : 是一个 32 位整型,由 BucketCodec 编码,各个二进制位的含意为:

    • 1-3 位:编码版本,以后是 001
    • 4 位:保留
    • 5-16 位:分桶 ID,由 0 开始。分桶 ID 是由 CLUSTERED BY 子句所指定的字段、以及分桶的数量决定的。该值和 bucket_N 中的 N 统一
    • 17-20 位:保留
    • 21-32 位:语句 ID
    • 举例来说,整型 536936448 的二进制格局为 00100000000000010000000000000000,即它是按版本 1 的格局编码的,分桶 ID 为 1
  • rowId : 是一个自增的惟一 ID,在写事务和分桶的组合中惟一
  • currentTransaction : 以后的写事务 ID
  • row : 具体数据。对于 DELETE 语句,则为 null

咱们能够留神到,文件中的数据会按 (originalTransaction,bucket,rowId) 进行排序,这点对前面的读取操作十分要害,这些信息还能够通过 row__id 这个虚构列进行查看:

SELECT row__id, id, name, salary FROM employee;

{"writeid":1,"bucketid":536870912,"rowid":0}    1       Jerry   5000
{"writeid":1,"bucketid":536870912,"rowid":1}    2       Tom     8000
{"writeid":1,"bucketid":536870912,"rowid":2}    3       Kate    6000

2.3、更新数据

UPDATE employee SET salary = 7000 WHERE id = 2;
这条语句会先查问出所有符合条件的记录,获取它们的 row__id 信息,而后别离创立 delete 和 delta 目录:

/user/hive/warehouse/employee/delta_0000001_0000001_0000/bucket_00000
/user/hive/warehouse/employee/delete_delta_0000002_0000002_0000/bucket_00000
/user/hive/warehouse/employee/delta_0000002_0000002_0000/bucket_00000

delete_delta_0000002_0000002_0000/bucket_00000 蕴含了删除的记录
原始 originalTransaction 为 1,currentTransaction 为 2 (简略的说,就是以后事务比之前的事务大,其实说白了就是之后对之前的数据进行一些变更操作,否则就是原始事务和以后事务是雷同的)

{"operation":2,"originalTransaction":1,"bucket":536870912,"rowId":1,"currentTransaction":2,"row":null}

delta_0000002_0000002_0000/bucket_00000 蕴含更新后的数据:

{"operation":0,"originalTransaction":2,"bucket":536870912,"rowId":0,"currentTransaction":2,"row":{"id":2,"name":"Tom","salary":7000}}

DELETE 语句的工作形式相似,同样是先查问,后生成 delete 目录

退出移动版