TiDB 事务限制详解

在2.1及之前的 TiDB 版本中,对于事务的限制是和其他关系型数据库而言比较特殊的地方,很多用户在使用过程中总是会感觉比较困惑,本文针对事务限制做一些详细的说明,希望能够帮助大家理解。

官方定义

由于 TiDB 分布式两阶段提交的要求,修改数据的大事务可能会出现一些问题。因此,TiDB 特意对事务大小设置了一些限制以减少这种影响:

每个键值对不超过 6MB

键值对的总数不超过 300,000

键值对的总大小不超过 100MB

详见PingCAP 官方文档,https://pingcap.com/docs-cn/sql/mysql-compatibility/


相信键值对应该比较容易理解,毕竟 TiDB 底层存储选用的是 rocksdb 引擎,一种基于 key-value 的存储结构。而每个键值对的大小和总大小限制分别是6MB 和100MB,这个应该也比较容易理解。关键在于每个事物包含键值对的总数不超过30W 这个经常会引起一些误解,下面做一些详细说明。

如何理解30W

很多人第一眼看上去,以为是一个事务涉及的行数不能超过30W,但其实不是这样的,首先需要了解 TiKV 对于结构化数据是如何转化为 key-value 结构存储的。

对于 key-value 结构的数据,可以认为结构如下

当插入一条数据时,tikv 是如何记录这条数据呢,包含以下几个步骤:

1、插入数据本身

2、插入唯一索引

3、插入普通索引

综上,当执行 insert 事务时,30W 限制需要除以所有索引的数量(包含主键和唯一索引)。


下面考虑当删除一条数据时,tikv 是如何处理的。首先需要明确,rocksdb 引擎所有的操作都是新增,所以删除也是插入,只是插入了一条 flag = del 的记录,具体情况如下:

1、插入数据本身的删除标记

2、插入唯一索引的删除标记

3、插入普通索引的删除标记

综上,当执行delete 事务时,30W 限制需要除以所有索引的数量(包含主键和唯一索引)。


更新比较复杂,放到最后来说明。首先来看,更新的是非主键且无索引字段的情况。

这种情况,只需要修改记录本身的内容即可,也就是下面一步:

1、插入数据本身即可

综上,非主键且无索引字段更新,30W 限制就是30W。


其次,来看更新的是非主键,但包含索引的字段情况。

1、数据本身

2、如果更新字段上有唯一索引

3、如果更新字段上有普通索引

综上,非主键但索引相关字段的更新,30W 限制需要除以(1 + 字段涉及索引数量 * 2)。


最后来看当更新的是主键字段的情况。从上面插入的描述中可以看出,无论是数据本身,还是索引,都包含了 pk,所以主键更新会触发所有的key 更新,具体如下:

1、数据本身

2、所有的唯一索引

3、所有的普通索引

综上,主键字段的更新,30W 限制需要除以(所有索引的数量 * 2)。

30W 键值对的转换

总结如下:

具体案例:

CREATE TABLE `t1` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` char(10) CHARSET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,

  `age` int(11) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `idx_name` (`name`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

以上面的简单表结构为例,该表有自增主键,外加1个普通索引,那么上面的事务限制对应的记录数为


事务的其他限制

除了上面 rocksdb 层的限制意外,tidb 中对于事务还有另外一个限制

1、参数 stmt-count-limit,默认值是5000。

StmtCountLimit limits the max count of statement inside a transaction.

也就是一个事务里面,默认最多包含5000条 SQL statement,在不超过上面 rocksdb 层的几个限制的前提下,这个参数可以修改 tidb 的配置文件进行调整。


2、另外在某些场景下,例如执行insert into  select 的时候,可能会遇到下面的报错

ERROR 1105 (HY000): BatchInsert failed with error: [try again later]: con:3877 txn takes too much time, start: 405023027269206017, commit: 405023312534306817    

这个主要是有一个隐藏参数,max-txn-time-use,默认值是 gc_life_time - 10s,也就是590

具体参考 PingCAP GitHub 上的文档:https://github.com/pingcap/tidb/blob/master/config/config.toml.example#L240

# The max time a Txn may use (in seconds) from its startTS to commitTS.# We use it to guarantee GC worker will not influence any active txn. Please make sure that this# value is less than gc_life_time - 10s.

所以我们要尽量保证一个事务在这个gc_life_time - 10s 的时间内完成,也可以通过调整 gc 时间 + 修改这个参数来避免这个问题,可能 tidb 的配置文件中没有放出这个参数,可以手动编辑,加入这个值。当然了,更好的办法应该是开启 tidb_batch_insert 参数来规避单个事务过大的问题。

如何绕开大事务的限制

官方提供内部 batch 的方法,来绕过大事务的限制,分别由三个参数来控制:

tidb_batch_insert

作用域: SESSION默认值: 0这个变量用来设置是否自动切分插入数据。仅在 autocommit 开启时有效。 当插入大量数据时,可以将其设置为 true,这样插入数据会被自动切分为多个 batch,每个 batch 使用一个单独的事务进行插入。

tidb_batch_delete

作用域: SESSION默认值: 0这个变量用来设置是否自动切分待删除的数据。仅在 autocommit 开启时有效。 当删除大量数据时,可以将其设置为 true,这样待删除数据会被自动切分为多个 batch,每个 batch 使用一个单独的事务进行删除。

tidb_dml_batch_size

作用域: SESSION默认值: 20000这个变量用来设置自动切分插入/待删除数据的的 batch 大小。仅在 tidb_batch_insert 或 tidb_batch_delete 开启时有效。 需要注意的是,当单行总数据大小很大时,20k 行总数据量数据会超过单个事务大小限制。因此在这种情况下,用户应当将其设置为一个较小的值。

针对 update 场景,官方还是建议通过 limit 的方式来循环操作,目前并未提供内部 batch update 的参数开关。

需要注意的是,开启了 batch 功能之后,大事务的完整性就没法保证了,只能保证每个批次的事务完整性。当然,数据库的最佳实践依然是由程序或 DBA 来控制事务的大小,尤其是针对分布式数据库,建议每个batch 控制在100条左右,高并发的写入,同时避免热点现象,才能发挥TiDB  分布式的优势。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容