方法一

来自网络搜索

思路: 创建一个触发器,在执行insert之前,查询id中数字部分最大的数,并拼接新id
优点: 无需额外自增id占用内存
缺点: 性能开销大,数据量越来越大,插入效率越来越低

-- 创建数据表
CREATE TABLE `tbl_school` (
  `id` char(12) NOT NULL DEFAULT '',
  `name` varchar(255) NOT NULL,
  `is_delete` tinyint(1) DEFAULT 0 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学校信息表';

-- 创建触发器
CREATE TRIGGER tbl_school_insert
  BEFORE INSERT ON tbl_school
  FOR EACH ROW
  SET NEW.id = CONCAT(
    'school_',
    LPAD(
      (SELECT IFNULL(MAX(SUBSTR(id, 8)) + 1, 1) FROM tbl_school),
      5,
      '0'
    )
  );

方法二

由方法一改良

思路: MAX(SUBSTR(id, 8))操作非常消耗算力,如果新增一列自增长主键auto_id,直接取最大的auto_id进行拼接,算力会小很多,且耗时固定
优点: 性能开销最低,查询时间稳定,表中原本就设计有自增长键非常合适
缺点: 需要额外新增一列,逼死强迫症

-- 创建数据表
CREATE TABLE `tbl_school` (
  `auto_id` INT AUTO_INCREMENT NOT NULL,
  `id` char(12) NOT NULL DEFAULT '',
  `name` varchar(255) NOT NULL,
  `is_delete` tinyint(1) DEFAULT 0 NOT NULL,
  PRIMARY KEY (`auto_id`)
) ENGINE=InnoDB COMMENT='学校信息表';

-- 创建触发器
CREATE TRIGGER tbl_school_insert
  BEFORE INSERT ON tbl_school
  FOR EACH ROW
  SET NEW.id = CONCAT(
    'school_',
    LPAD(
      (SELECT IFNULL(MAX(auto_id) + 1, 1) FROM tbl_school),
      5,
      '0'
    )
  );

方法三

由方法一、方法二延伸

思路: 方法一的时间主要消耗在,每次查询拼接的数字时,都会把表中所有id进行截取之后取max,如果直接按id倒序取第一条的id,即当前的最大id进行截取后取数,会少很多的字符串截取排序的查询性能消耗。
优点: 无需额外自增id占用内存,性能开销很低,查询时间稳定
缺点: 时间相较于方法二略高一点,但取舍之下性价比最高

-- 创建数据表
CREATE TABLE `tbl_school` (
  `id` char(12) NOT NULL DEFAULT '',
  `name` varchar(255) NOT NULL,
  `is_delete` tinyint(1) DEFAULT 0 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学校信息表';

-- 创建触发器
CREATE TRIGGER tbl_school_insert
  BEFORE INSERT ON tbl_school
  FOR EACH ROW
  SET NEW.id = CONCAT(
    'school_',
    LPAD(
      (SELECT IFNULL( (SELECT (SUBSTR(id, 8) + 1) FROM tbl_school ORDER BY id DESC LIMIT 1) , 1)),
      5,
      '0'
    )
  );

性能对照测试

批量插入数据sql参照: https://blog.lakesideknight.com/archives/176

方法一:插入第1-1000条数据,耗时2.78秒

image-1671031739281.png

本示例可能不是最优解,若有更好的实现方法请在评论区分享给大家。