MySQL在最大化时重用丢失的主键int值

问题描述

我们的一个表意外地用完了 ID。快速浏览一下表格,我可以看到并非所有 Id 都已使用。我认为我们可能出于某些原因删除了数据。

我一直在读到 MysqL 的 auto_inc 字段的性质意味着它总是为下一个 Id 变为 +1。

有没有办法告诉它使用未使用的 ID?

我一直在这里阅读:https://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html 但我不是一个超级数据库开发人员,我真的不知道这是否会达到我所希望的。

我们的第一个计划是将 Id 更改为 Unsigned() 并获得额外的几十亿行。但这是对我们不应该接近的问题的快速解决方案。 该表在生产中不断使用,但我们的系统确实有一个“重试”概念。因此,如果这张桌子暂时失效,那对我们来说没问题。

任何指针或想法将不胜感激。 干杯

解决方法

回答您的问题:

不,没有办法告诉 MySQL 的自动增量生成“填补空白”表中的值。

即使您尝试更改表以重置下一个增量值,它也会立即将自身调整为当前 MAX(id)+1。不会生成小于表中当前最大自动增量的自动增量值。

您可以执行 INSERT 来覆盖自动增量并自己指定一个值。但是由您来查找未使用的值。

这引入了竞争条件。即使您检查未使用的值,其他一些客户端也可以在您读取该值后立即获取它,然后再将其用于 INSERT。

为了避免竞争条件,您必须锁定整个表,以防止另一个客户端插入。然后您的会话可以执行查询以查找缺失值,然后插入,然后解锁表。

自动增量不填补空白的限制有几个很好的理由。

  • 它简化了内部实现。它只需要跟踪每个表的一个值。更简单的实现通常意味着更少的错误机会。

  • 搜索下一个值不需要表锁。分配下一个值是通过一个简短的互斥锁实现的。这允许许多并发客户端自由插入,无需等待。

  • 差距可能有很好的理由。

这个场景有点复杂,但它说明了这样的场景是可能存在的:

假设 users 表中的 id 12345 对应于因向其他用户发送骚扰电子邮件而被禁止的用户。他们的帐户被禁止和禁止,并且他们帐户的 users 表中的行被删除。稍后,如果您发现该差距并假设它从未使用过,那么您将该 ID 12345 分配给下一个新用户。不幸的是,它们现在与被禁用户的 ID 相关联。

然后,不常查看电子邮件的人发现了其中一封原始滥用电子邮件。收件人抱怨用户 12345。但该 ID 现在属于新的无辜用户,他们不应该被指责发送骚扰电子邮件。

,

如果您的 AUTO_INCREMENT 值由于多次删除而接近最大 INT 值,那么切换到 BIGINT 应该是最简单的解决方案。您可以估计,烧掉所有 BIGINT 值需要多长时间。如果以年为单位的估计数字是一个您不知道名字的数字,那么您应该可以安全一段时间。

还有其他选项,如 UUID。但如果 INT 到现在为止都运行良好,那么 BIGINT 也应该如此。