关于tidb的主键选择

关于tidb的主键有四种选择

  1. AUTO_INCREMENT
  2. UUID
  3. AUTO_RANDOM
  4. 不设置,TIDB默认生成隐藏主键
    我的问j题有两个
  5. 参照文档都有说到后面三种都有助于避免读写热点问题,那么使用哪一种更好?哪一种更有利于避免热点问题,及哪一种性能更高?是否有人做过压测?
  6. AUTO_RANDOM属性是TIDB特有的,我用常用的数据库工具导出建表sql,建表SQL语句里不会包含AUTO_RANDOM,目前市面上是否有可以支持这一属性的数据库客户端工具?
    希望得到你的帮助,谢谢!
  • 问题1:

    • 场景特征: 场景对于业务支撑的量级是有大的差别的,但是有更多的业务系统是要做兼容考虑的,那么迁移的数据保证前后逻辑的一致性,必须要考虑主键的处理方案
    • 结论:请根据自己的业务场景,去做相应的选择,如果不考虑兼容性问题,可采用性能最好的方案,否则需要做很多兼容性的处理,即使是手工的…
  • 问题2:
    市面上大部分工具都支持了,tidb特性是依靠注释的方式来描述的,只要在开启client 链接之前,开启注释生效即可。官方推荐这样一款工具 mycli,请考虑

感谢你的回答,继续请教下,在一个全新开发的场景,没有历史数据兼容性问题,哪一种是性能最好的方案呢?

性能问题就取决于一点,数据是否能够均衡到每个节点上,进行读写,避免出现写偏斜和读偏斜
说人话就是不让所有的请求打到单个节点实例上,这样分布式的处理优势就变成了单机,这就是最大的问题点
那么这个问题点关联的核心是什么?
答案: 热点

请参考以下的文档:
https://docs.pingcap.com/zh/tidb/stable/high-concurrency-best-practices
https://docs.pingcap.com/zh/tidb/stable/configure-load-base-split
https://docs.pingcap.com/zh/tidb/stable/troubleshoot-hot-spot-issues#tidb-热点问题处理

其实官方的文档已经给出了答案,但是这个答案和场景还是关联的,需要知晓 大概的数据规模,这样才能实现更好的数据分片。不过,就算初期不太清楚,定义了不太够的规模,也关系不大,可进行手工进行调整,实现这个自动分片的能力,请参考 https://docs.pingcap.com/zh/tidb/stable/auto-random

早期的版本,是没有auto-random这个特性的,为了保证适应更多更好的场景,能够简单的使用,才逐渐形成了这个特性。 :+1:

1 个赞

纯理论的建议 避免uuid autoincrement ,建议使用 autorandom。然后还是那么多的系统在使用uuid当主键。

首先你要确定你的io是否特别高会有瓶颈,如果没有就用 AUTO_INCREMENT
其次看tikv数量,如果就3副本3tikv,那用 AUTO_RANDOM意义也不是很大

我这边以前历史在MySQL迁移的表都是 AUTO_INCREMENT迁移过来手工打散了,后面再新建的都是用的AUTO_RANDOM了,虽然不再拥有自增的属性

1,最推荐的是 AUTO_RANDOM,聚簇表用这个设置主键,根据主键的读/写会少一次回表,性能会高一些,但是这个对上下游迁移的场景来说不太友好。
2,AUTO_INCREMENT不做表改造的情况下,一定会有热点,如果写入大的表必须用非聚簇表+ SHARD_ROW_ID_BITS改造一下。根据主键的读/写会比AUTO_RANDOM多一次回表,但是对迁移来说比较友好。
3,uuid做主键,最佳实践看
https://docs.pingcap.com/zh/tidb/stable/uuid#最佳实践
4,不设置,TIDB默认生成隐藏主键。
不设置以消除热点的说法不知从何而来。
总体来说,消除热点就是聚簇表+AUTO_RANDOM,非聚簇表+SHARD_ROW_ID_BITS+PRE_SPLIT_REGIONS

  1. AUTO_INCREMENT
    自增在并发写入场景下,行数据会集中在单个 region 中,造成热点,所以不适合高并发写入场景

  2. UUID
    字符串的,而且挺长的 36 个字符,个人感觉性能不如数字,可以测下

  3. AUTO_RANDOM
    为了解决高并发写入场景产生热点问题而出的功能,只能解决数据行热点,索引热点解决不了。

  4. 不设置,TIDB默认生成隐藏主键
    这个默认也是自增,可以使用 shard rowid bit 功能解决热点问题,原理与auto random类似,同样解决不了索引热点问题

  5. 参照文档都有说到后面三种都有助于避免读写热点问题,那么使用哪一种更好?哪一种更有利于避免热点问题,及哪一种性能更高?是否有人做过压测?
    个人感觉最好的应该是AUTO_INCREMENT,聚簇表一行少写一个key,能避免热点问题

  6. AUTO_RANDOM属性是TIDB特有的,我用常用的数据库工具导出建表sql,建表SQL语句里不会包含AUTO_RANDOM,目前市面上是否有可以支持这一属性的数据库客户端工具?
    我用 DBaver 看表 DDL 是可以看到的,通过 show create table 语句看表结构的应该都是可以的。

1 个赞

根据具备的业务来确定。
比如小的配置表,数据几乎静止,可以选用AUTO_INCREMENT或UUID;
比如数据量大且写频繁的表,使用AUTO_RANDOM比较合适,可以解决写热点

AUTO_INCREMENT:建议在小表,数据量不多,调用不频繁,不会出现热点块的表,可以用
UUID :varchar 类型的,不建议用大表,因为主键长,占用空间大,搜索需要时间
AUTO_RANDOM,可以用,避免热点,也有缺点,手工插入有值的数据需要修改参数
不设置,TIDB默认生成隐藏主键,一般建议都要设置主键,只是varchar类型的主键类似于mysql的二级索引,回去调用隐藏的不可见的内部索引

varchar 类型的主键,在数据量比较大的时候,非聚簇表使用SHARD_ROW_ID_BITS打散就好了
bigint类型的主键,聚簇表,建议只用随机数,应用改造一下,产生随机数据插入

如果是高效ssd盘的情况下。大多情况用auto_increment就够了。如果预期的写入单块ssd扛不住。那就auto_random。

:flushed:一点都不考虑业务主键么?

1 个赞

主键一般不推荐使用有业务含义的字段。

有业务含义的字段也没问题,不要太教条了。
聚簇表用由业务含义的可以少个二级索引,写入查询都会更快

不能用业务主键代替非业务主键
因为业务主键,需要包含业务含义,所以只能是varchar类型,并且是按照一定规则生成的,必定是无序的。这两点,都是不适合作为表数据的主键的原因。也决定了业务主键不能代替非业务主键,作为数据表的真正意义上的主键。

只能是varchar类型从何说起?
按照一定规则生成的,必定是无序的 ,既然有规则了,肯定有有序的。规则不能是随机的算法吧

我们用一堆字段联合主键,也没啥问题

:joy:那可能真的不一样,我们这边的开发规范是,能用业务主键的尽量用业务主键,因为一个主键查询加速,就值得我们去用业务主键了。 :yum:

1 个赞

:thinking:为什么呀,比如业务最常用的单号作为主键,查询肯定比作为索引快吧。
以前用sqlserver的时候,要求是业务主键 用 聚簇唯一索引,guid这种 用非聚簇主键。

1 个赞

:thinking:这里有一个疑问,我记得主键的选择会影响读写的性能,业务主键的读性能比较好,随机主键的写性能比较好?

1 个赞