TiDB 中的自增主键有哪些使用限制,应该如何避免?

server/2024/9/22 3:19:27/

大家好,我是V 哥,在TiDB中使用自增主键时,确实存在一些限制和潜在的热点问题,今天的文章来聊一聊 TiDB中的自增主键要怎么做。

以下是一些使用限制和如何避免它们的方法:

  1. 自增主键的限制

    • 必须在主键或唯一索引列上定义。
    • 只能定义在整型、FLOAT或DOUBLE类型的列上。
    • 自增列不支持DEFAULT定义。
    • 不支持使用ALTER TABLE增加AUTO_INCREMENT属性。
    • 默认不允许移除AUTO_INCREMENT属性,可以通过@@tidb_allow_remove_auto_inc来控制是否允许删除自增属性。
    • 可以保证自增不唯一,无法保证顺序。
  2. 避免自增主键限制的方法

    • 使用AUTO_RANDOM:TiDB提供了AUTO_RANDOM属性,可以在建表时替代AUTO_INCREMENT使用,这样TiDB会生成随机分布的ID,从而避免写入热点问题 。
    • 使用SHARD_ROW_ID_BITS:对于非聚簇索引主键或没有主键的表,TiDB会使用一个隐式的自增RowID。通过设置SHARD_ROW_ID_BITS,可以把RowID打散写入多个不同的Region,缓解写入热点问题 。
    • 使用分布式ID生成器:例如Snowflake算法,可以在应用层生成唯一的ID,避免依赖数据库的自增主键。
    • 使用UUID:可以在应用层生成UUID作为主键,但需要注意UUID的性能影响。
    • 使用Sequence序列:TiDB支持Sequence序列,可以在创建表时定义Sequence,然后使用Sequence来生成唯一的ID。

使用 AUTO_RANDOM

在TiDB中,AUTO_RANDOM是用于解决自增主键热点问题的一种方法。以下是一个具体的业务场景案例和操作步骤:

业务场景
假设你有一个高并发的在线服务,需要为每个服务实例生成一个唯一的标识符。如果使用传统的AUTO_INCREMENT自增主键,大量的写入操作可能会导致写入热点,因为所有的写入都会尝试在最后一个Region上进行,从而影响性能。

解决方案

  1. 创建表时使用AUTO_RANDOM
    在创建表时,将主键列设置为AUTO_RANDOM。例如,你可以执行以下SQL语句来创建一个新表:
   CREATE TABLE service_instances (id BIGINT PRIMARY KEY AUTO_RANDOM,instance_name VARCHAR(255),created_at TIMESTAMP);

这样,每当插入新行而没有指定id值时,TiDB会自动生成一个随机的id值。

  1. 插入数据
    当插入新服务实例时,不需要手动指定id值,TiDB会自动为每个实例生成一个唯一的id
   INSERT INTO service_instances (instance_name, created_at) VALUES ('ServiceInstanceName', NOW());

这将利用AUTO_RANDOM属性生成一个随机的id,从而避免写入热点。

  1. 获取最后插入的ID
    如果你需要获取最后插入的id,可以使用LAST_INSERT_ID()函数:
   SELECT LAST_INSERT_ID();

这将返回最近一次由TiDB隐式分配的AUTO_RANDOM值。

咱们可以使用TiDB的监控工具,如Grafana,监控AUTO_RANDOM字段的性能。注意观察是否有任何写入热点的迹象,如某个TiKV节点的负载明显高于其他节点。根据监控结果调整策略。

需要注意的是:

  • 不要显式地为AUTO_RANDOM字段插入值,除非打开了@@allow_auto_random_explicit_insert系统变量,并且你知道你在做什么。错误的显式赋值可能会导致值耗尽。
  • AUTO_RANDOM只能用于BIGINT类型的主键列,并且不支持与AUTO_INCREMENT同时使用。

使用 SHARD_ROW_ID_BITS

业务场景案例

假设你运营一个电商平台,需要处理大量的订单数据。每个订单都需要一个唯一的订单号,而且订单数据写入数据库时必须均匀分布,以避免写入热点。如果使用自增主键,大量的写入操作可能会集中在单个TiKV节点上,导致写入热点问题。

解决方案

  1. 创建非聚簇索引表

    创建订单表时,不使用自增主键,而是使用SHARD_ROW_ID_BITS来打散行ID,从而避免写入热点。

   CREATE TABLE orders (order_id INT PRIMARY KEY NONCLUSTERED,product_id INT,quantity INT,created_at TIMESTAMP,INDEX product_idx (product_id)) SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS=3;

这里SHARD_ROW_ID_BITS = 4表示行ID会被打散到16个分片中,PRE_SPLIT_REGIONS=3表示在表创建后会预先切分为8个Region。

  1. 插入数据
    当创建订单时,不需要手动指定order_id,TiDB会自动为每个订单分配一个唯一的行ID。
   INSERT INTO orders (product_id, quantity, created_at) VALUES (101, 2, NOW());

同样,我们使用Grafana,监控orders表的性能。注意观察是否有任何写入热点的迹象,如某个TiKV节点的负载明显高于其他节点。根据监控结果调整SHARD_ROW_ID_BITS的值。

需要注意的是:

  • 不要显式地为行ID插入值,让TiDB自动分配。
  • 根据业务并发度来设置合适的SHARD_ROW_ID_BITS值,以尽量解决热点Region无法打散的问题。

问题来了,如何根据业务增长调整 'SHARD_ROW_ID_BITS' 的值以优化数据库性能?

在TiDB中,SHARD_ROW_ID_BITS是一个表属性,用于设置隐式_tidb_rowid分片数量的bit位数,以此来解决写入热点问题。这个属性可以在创建表时指定,也可以用来修改现有表的行为。

调整SHARD_ROW_ID_BITS值的步骤

  1. 评估当前业务量和增长趋势
  • 监控当前业务对数据库的写入模式和数据增长速度。使用Grafana监控TiDB的写入流量和热点情况。
  1. 决定SHARD_ROW_ID_BITS的值
  • 根据业务增长预测和当前写入模式,决定一个合适的SHARD_ROW_ID_BITS值。例如,如果当前设置为4(分成16个分片),但写入压力仍然很高,可以考虑增加该值。
  1. 修改表属性
  • 使用ALTER TABLE语句来修改SHARD_ROW_ID_BITS值:
     ALTER TABLE your_table_name SHARD_ROW_ID_BITS = new_value;
  • 其中new_value是你基于业务增长评估后决定的新值。
  1. 预切分区域
  • 为了确保数据能够均匀分布,可以使用PRE_SPLIT_REGIONS选项在建表后预先切分出一定数量的Region:
     CREATE TABLE t (a int, b int) SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS=3;
  • 这里的PRE_SPLIT_REGIONS=3表示建完表后提前切分出8个Region。
  1. 监控调整后的效果
  • 调整SHARD_ROW_ID_BITS后,继续使用Grafana监控系统性能,特别注意写入流量的分布情况。
  1. 根据需要进一步调整
  • 如果写入热点仍然存在,可能需要进一步增加SHARD_ROW_ID_BITS的值,或者考虑其他优化措施。

需要注意的是:

  • 增加SHARD_ROW_ID_BITS的值会增加Region的分裂数量,可能会对TiDB集群的性能和资源使用产生影响。
  • 调整SHARD_ROW_ID_BITS值时,需要确保PD调度器不会因为小Region合并策略而将Region重新合并。

最后

关于使用分布式ID生成器,比如雪花算法,还有使用UUID和使用Sequence序列,这里V 哥就不再介绍了,与 MySQL 一致。因此,在 TiDB 中提供了AUTO_RANDOM 和 SHARD_ROW_ID_BITS来解决热点问题,好用的很。


http://www.ppmy.cn/server/120099.html

相关文章

网络丢包定位记录(二)

网卡驱动丢包 查看:ifconfig eth1/eth0 等接口 1.RX errors: 表示总的收包的错误数量,还包括too-long-frames错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。 …

Hugging Face NLP课程学习记录 - 0. 安装transformers库 1. Transformer 模型

Hugging Face NLP课程学习记录 - 0. 安装transformers库 & 1. Transformer 模型 说明: 首次发表日期:2024-09-14官网: https://huggingface.co/learn/nlp-course/zh-CN/chapter1关于: 阅读并记录一下,只保留重点…

java和kotlin版本对照表

Java 和 Kotlin 是两种广泛使用的编程语言,特别是在 Android 开发领域。虽然它们有不同的语法和特性,但它们在很多方面是可以互操作的,尤其是在同一个项目中使用时。了解 Java 和 Kotlin 的版本对应关系可以帮助开发者更好地进行跨语言开发和…

React【1】【ref常用法】

文章目录 前言用途1. 储存2. 储存dom句柄ref 前言 react组件每次调用setState的时候都会重新执行函数组件或者class组件 用途 1. 储存 每次调用setState时,组件函数都会重新执行。下面这种情况点击提交后,再点击取消,会发现定时器trimId1仍…

机器翻译之数据处理

目录 1.导包 2.读取本地数据 3.定义函数:数据预处理 4.定义函数:词元化 5.统计每句话的长度的分布情况 6. 获取词汇表 7. 截断或者填充文本序列 8.将机器翻译的文本序列转换成小批量tensor 9.加载数据 10.知识点个人理解 1.导包 #导包 import o…

linux 基础知识 什么是僵尸进程?有什么影响?如何解决?

linux 系统僵尸进程 在Linux系统中,僵尸进程(Zombie Process)是一种特殊的进程状态,它指的是一个已经完成执行的进程,其父进程尚未通过wait()或waitpid()系统调用来回收其资源和状态信息。 僵尸进程本身并不占用CPU和…

智能自行车码表:基于2605C语音芯片的创新开发方案

一、开发背景 随着科技的飞速发展和人们对健康生活的追求,自行车骑行已成为一种广受欢迎的绿色出行方式。智能自行车码表作为骑行者的得力助手,不仅记录骑行数据,还逐渐融入了更多智能化功能。然而,传统码表在语音提示、多语种支持…

使用python-pptx将PPT转换为图片:将每张幻灯片保存为单独的图片文件

哈喽,大家好,我是木头左! 本文将详细介绍如何使用python-pptx将PPT的每一张幻灯片保存为单独的图片文件。 安装python-pptx库 需要确保已经安装了python-pptx库。可以通过以下命令使用pip进行安装: pip install python-pptx导入所需库 接下来,需要导入一些必要的库,包…