当前位置: 首页 > news >正文

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

大家好,我是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.mrgr.cn/news/30930.html

相关文章:

  • 【LeetCode】【算法】64. 最小路径和
  • 在CentOS下安装RabbitMQ
  • 软件设计师-操作系统
  • 【数据管理】DAMA-数据建模和设计
  • Vue.js 高质量翻页功能的完整开发指南
  • 基于SpringBoot+Vue实现剧本杀服务平台【源码+LW+PPT+部署】
  • HCL Domino 14.5EAP1快问快答
  • 解决Filament中使用ARCore出现绿色闪屏的问题
  • 力扣150题——多维动态规划
  • 【高阶用法】uniapp的i18n多语言模块修复与增强(Typescript)
  • numpy之随机抽样函数np.random.choice()
  • 阿里云大模型,这次云栖大会又“卷”出了新高度!
  • 【PostgreSQL教程】PostgreSQL详细介绍
  • Bayes networks可视化工具-Netica
  • 【C++】——多态详解
  • STM32cubeMX + VScode开发GD32移植(HAL库通用),保姆级!!!!!!!
  • 住宅代理IP如何提高 IP声誉?
  • BMW宝马品牌各车系车轮轮毂螺栓扭矩参数
  • AirTest 基本操作范例和参数解释(一)
  • 浏览网站记录怎么查?(如何查看浏览历史记录)三分钟学会五种方法!
  • 算法.图论-并查集上
  • 使用 Go 语言实现简单聊天系统
  • 【AI视频】Runway Gen-2:图文生视频与运动模式详解
  • 微信小程序. tarojs webView的 onload 事件不触发
  • 解决哈希冲突的方法
  • 1--SpringBoot外卖项目介绍及环境搭建 详解