背景
由于TiDbiB是一个支持ACID的分布式数据库,受限于事务大小的严格控制,日常Hive与TiDB大批量数据交互的过程中,常常会出现如下错误:
Error Code:8004.transaction is too large
原因
以下摘自TiDB官方解释文档
由于分布式事务要做两阶段提交,并且底层还需要做Raft复制,如果一个事务非常大,会使得提交过程非常慢,并且会卡住下面的Raft复制流程。为了避免系统出现被卡住的情况,对事务的大小做了限制:
- 单个事务包含的SQL语句不超过5000条(默认)
- 单条KV entry不超过6MB(SQL层面:单行数据不大于6MB)
- KV entry的总条数不超过30w(SQL层面:总的行数*(1+索引个数)<30w)
- KV entry的总大小不超过100MB(SQL层面:一次提交的全部数据小于100MB)
注意:无论是大小限制还是行数限制,还要考虑TiDBit做编码以及事务额外Key的开销,建议每个事务的行数不超过200行,且单行数据小于100k,否则可能性能不佳。
解决方案
insert&select
--开启隐藏函数
set @@session.tidb_batch_insert = 1;
--事务完成后,关闭
set @@session.tidb_batch_insert = 0;
注意:insert会把大事务分批执行,避免超时的同时会导致事务原子性的丢失。
update&delete
for i from 0 to 23:
while affected_rows <> 0:
delete * from table where insert_time >= i:00:00 and insert_time < (i+1):00:00 limit 5000;
affected_rows = select affected_rows()
注意:通过循环方式删除数据可能会导致速度越来越慢,因为每次删除都是从前向后遍历,前面数据删除后,短时间内会残留删除标记(后续会被gc掉),从而影响后面的Delete语句。因此建议将where条件细化,见上伪代码。