IE盒子

搜索
查看: 129|回复: 1

MySQL 的自增 ID 用完了该怎么办?

[复制链接]

3

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2023-1-1 19:32:48 | 显示全部楼层 |阅读模式
假设前提条件


  • 假设字段类型设计不合理
  • 最大程度保证线上程序正常运行
  • 保证数据不丢失
  • 保证原ID不变改
自增ID消耗完可能原因:

  • 业务写入数据量巨大
  • 频繁写入、删除,继续写入再删除...
  • 历史原因 ...
假设自增ID字段数据类型不符合业务实际使用场景,如使用TINYINT、SMALLINT、MEDIUMINT、INT
MySQL Integer 字段数值范围
类型字节数 (Bytes)有符号最小值无符号最小值有符号最大值无符号最大值
TINYINT1-1280127255
SMALLINT2-3276803276765535
MEDIUMINT3-83886080838860716777215
INT4-2147483648021474836474294967295
BIGINT8-2630263-1264-1
解决方法

1. 直接修改表字段类型

如果使用TINYINT、SMALLINT(不论是否无符号),大胆改表结构。可以根据实际业务预估的数据量修改为更大的类型,因为数量本身不大,锁表时间也不会很长。
ALTER TABLE `table_name` CHANGE `id` `id` bigint(20) Unsigned NOT NULL auto_increment;
Query 1 ERROR: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
2. 重命名迁移:大于MEDIUMINT的数据类型,分步修改结构

此时表数据量已经比较大。如需要保证线上业务正常,直接修改表结构,在修改过程中MySQL可能会进行重建表,以及数据逐行复制等操作,将导致表长时间无法写入和读取
此方法优点:


  • 只有在重命名是才锁定表,而重命名本身很快
  • 导入数据分两步:导入存量数据到新表;锁定表写入并导入新增数据
  • 完整保留原ID和数据
重命名迁移


  • 创建与原表结构一致的新表,ID字段修改为合适的类型,为表创建合适的索引
  • 将原表数据写入新表
  • 保证在同一事务执行,且锁定旧表。重命名旧表为_bak,重命新表为旧表名
-- 基于原表结构创建一个新表
CREATE TABLE `stats_macro_indicator_new` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `dt` date DEFAULT NULL COMMENT '日期',  
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `IDX_MULITPLE_COLS` (`dataset_code`,`indicator_code`) USING BTREE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

--导入已有数据到新表
INSERT INTO stats_macro_indicator_new
SELECT * FROM stats_macro_indicator

-- 重命名,ALGORITHM = INSTANT(MySQL8.0)后续说明
-- 禁用自动提交事务
SET autocommit=0;
-- 锁定原表数据写入
LOCK TABLES stats_macro_indicator WRITE ;
--开始事务
START TRANSACTION;
--补全数据
INSERT INTO stats_macro_indicator_new SELECT * FROM stats_macro_indicator WHERE id > (SELECT MAX(id) FROM stats_macro_indicator_new);
--重命名(LOCK = DEFAULT 可以不需要)
ALTER TABLE stats_macro_indicator RENAME TO stats_macro_indicator_bak, ALGORITHM = INSTANT , LOCK = DEFAULT;
ALTER TABLE stats_macro_indicator_new RENAME TO stats_macro_indicator, ALGORITHM = INSTANT, LOCK = DEFAULT;
COMMIT;
UNLOCK TABLES;

延伸阅读 - MySQL 8.0:InnoDB Instant 即时添加列

从MySQL 5.6 开始支持 INPLACE DDL的版本。在这之前执行 DDL的唯一方法是逐行复制。INPLACE DDL 主要由 InnoDB 处理,而 COPY 逐行在服务器层处理
8.0开始 MySQL支持 ALGORITHM=INSTANT 即时算法,INSTANT算法的好处是只在数据字典中进行元数据更改。在更改期间不需要获取元数据锁,不接触表的数据。无需为 INSTANT 算法指定 LOCK。在 ALGORITHM=INSTANT 的情况下,LOCK 不能设置为 DEFAULT 以外的任何其他值,否则会出现错误。



各DDL算法对比

InnoDB 支持INSTANT算法的DDL操作:


  • 修改索引
  • 重命名表(以 ALTER 方式)
  • 设置/删除列的默认值
  • 修改列(列数据类型修改不支持)
  • 添加/删除虚拟列(可以理解为自动计算列)
  • 添加列(非生成的)—— 即时添加列
使用 ALGORITHM=INSTANT 在单个语句中执行以上多个DDL的组合
值得一提,值得一赞的是INSTANT ADD COLUMN 补丁由腾讯游戏 DBA 团队贡献
更多关于INSTANT介绍:MySQL 8.0: InnoDB now supports Instant ADD COLUMN
回复

使用道具 举报

2

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2025-4-10 05:46:27 | 显示全部楼层
看起来好像不错的样子
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表