【问题标题】:Fastest and Safest Way to Emulate Auto-Increment using MAX in InnoDB在 InnoDB 中使用 MAX 模拟自动增量的最快和最安全的方法
【发布时间】:2019-01-24 07:22:35
【问题描述】:

假设我们有一个具有以下架构的表:

CREATE TABLE Persons (
sid int NOT NULL AUTO_INCREMENT,
groupName varchar(255) NOT NULL,
userIdInGroup int,
PRIMARY KEY (sid));

我们希望根据该组的最后一个 userId 为同一组中的每个新用户分配一个自动递增的 userId,即我们希望在每个组中模拟一个自动递增的 userId。

由于考虑到 MAX(userIdInGroup) 我们要插入新的 userId,我们需要将 select 和 insert 包装到事务中。像这样的:

START TRANSACTION
SET @a = (SELECT MAX(userIdInGroup) FROM Persons WHERE groupName= 'Foo') +1;
INSERT THE NEW ROW USING userIdInGroup = @a
COMMIT 
  1. 只是在事务中选择 MAX 是安全的,还是我们需要通过 SELECT FOR UPDATE 锁定某些内容?
  2. 有没有办法绕过事务仍然保持一致?

【问题讨论】:

  • 我只是觉得这是个坏主意。只需存储一个自动递增的 id,并在需要时计算组中的位置..

标签: mysql sql transactions


【解决方案1】:

我不是 MySql 人,但我确实对其他数据库有足够的经验,知道这是一个非常糟糕的主意。这个UserIdInGroup 可以很容易地用row_number 计算出来:

SELECT sid, 
       groupName, 
       ROW_NUMBER() OVER(PARTITION BY groupName ORDER BY sid) AS userIdInGroup
FROM Persons

除了滚动您自己的自动增量通常最终会给出错误的数字(尤其是在多线程环境中)这一事实之外,您可以轻松计算的内容(无论是在代码方面还是在性能方面)都不应该被存储无论如何。

【讨论】:

  • 您只能在 MySQL 8+ 中执行此操作,但对于旧版本还有其他技术。原理还是一样的
  • @Strawberry 正如我所说,我不是 MySql 人。随意使用较低版本的解决方案编辑我的答案,或使用该解决方案添加另一个答案。
  • @ZoharPeled 我知道这种类型的自动增量是一个坏主意,但它对我们的业务来说是一种力量,可以用最快的方法在每个组中提供顺序 ID。
猜你喜欢
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 2023-03-15
相关资源
最近更新 更多