java MySQL:8.0.31 -使用几个月后ID字段出现大的缺口(数千)[已关闭]

jhkqcmku  于 2022-12-21  发布在  Java
关注(0)|答案(2)|浏览(151)
    • 已关闭**。此问题需要超过focused。当前不接受答案。
    • 想要改进此问题吗?**更新此问题,使其仅关注editing this post的一个问题。

昨天关门了。
Improve this question
我们在mysql8.0.31发布版本的多个表中看到了带有auto_increment的主键列的大间隙(默认值为-innodb_autoinc_lock_mode = 2("交错"锁模式))。
我们有"订单"表(id bigint)和"订单行项目"表(id bigint)。

TABLE_NAME          | CURRENT AUTO_INCREMENT    |  TABLE ROW COUNT
order               |   27504                   |        1367
order_line_items    |  430930                   |       34970

我们总共有1367个订单行,其当前自动增量值为"27504",34970个订单行(订单行项目行),其当前自动增量值为"430930"。我们在API调用中的同一事务中保存订单和order_line_items(可能会出现错误,导致事务回滚)。

    • 差距:**

订单表的差距持续发生了1 - 2天,一旦我们注意到,并回到增加'1'再次截至今天。跳跃是一起发生在集群连续(检查下面),并回到增加'1'。

Order table gap details:

id    |  difference from previous 'id'
-------------------------------------
27489   1
27488   1
27487   1
27486   232
27254   232
27022   693
26329   240
26089   401
25688   175
25513   348
25165   864
24301   7656
16645   1709
14936   184
14752   13
14739   541
14198   82
14116   215
13901   68
13833   117
13716   140
....
1468    1
1467    10
1457    1
1456    1
1455    1
1454    9
1445    1
1444    1
1443    1
1442    1
1441    1
    • 意见:**

1.我们使用(OpenJPA)对ID使用配置(@Id,@GeneratedValue(strategy = GenerationType. IDENTITY)。代码中没有设置ID。
1.我们在其他表中也看到了相同的模式。我们测试了相同的API,用20个线程并行创建相同的表,但我们没有发现两个表的创建id存在类似的大差距。
1.直到id:1445(我们有1225行的计数)在订单表中,我们没有看到任何问题与更大的跳转。1445,我们开始看到订单表中的多次跳跃,直到27487,持续1 - 2天。
1.我也理解API调用中事务的回滚可以增加自动增量值,但是与总记录相比,多次更大的跳跃似乎是不可理解的。

    • 问题:**

1.有没有人知道这是什么原因?为什么ID在订单表中的总记录数低于1367的情况下却以数千的数量跳跃(例如,上例中的7656、1709)?
1.我看到这种情况发生在多个集群的岛屿的id跳跃和开始一个接一个地创建回来(像上面的例子)。这是否涉及任何其他内部处理的mysql数据相关进程。?。这是一个可能的错误mysql?
1.什么可以导致'mysql'像这样跳得更高(例如,批量插入,共享锁可以导致这种情况吗)?.我如何在本地模拟这个问题?.
任何建议都会很有帮助。

    • 更新:**多API调用已经完成,但由于客户端的意外重试导致ID中的巨大差距,因此在API级别失败。谢谢大家。
hfyxw5xn

hfyxw5xn1#

Id“间隙”可能由于以下几个原因而发生:

  • 如果INSERT失败,例如与另一个约束条件(如UNIQUE或FOREIGN KEY)冲突,则不会撤消ID的生成。不会插入行,但ID仍会递增,因此值会“丢失”。

我曾经帮助过一个客户解决过这样的问题。他们在users表中的用户名中有一个UNIQUE约束,有些人一直试图使用现有的用户名在网站上注册新用户。这种情况每天都在发生,而且还在不断增加,所以最终每天大约有1500个ID“丢失”。

  • 如果INSERT成功,但由于某种原因应用程序回滚了事务。
  • 如果auto_increment_increment被设置为1以外的值,这是一个可以由任何会话临时设置的选项,因此您可能在MySQL服务器配置文件中看不到它,但它可能在应用程序代码中。
  • INSERT指定了一个比下一个更大的id值更大的值,覆盖了自动增量。自动增量不会生成一个比表中最大值更小的值,所以如果INSERT指定了一个更大的值,那么下一个INSERT将更大。它不会填充它留下差距。
  • 有人运行了ALTER TABLE ... AUTO_INCREMENT=...并更改了表的当前next id值。
  • InnoDB错误。这是罕见的,但据报道,有时表会“跳过”自动增量值,而不是严格地按1递增。自动增量保证唯一的值,但不保证连续的值。
6pp0gazn

6pp0gazn2#

好吧,对于初学者,我不会开始检查插入。他们在这里几乎没有错。插入是如何完成的?我希望如果API调用失败,您将回滚,否则提交,对吗?但请记住如果事务失败,序列不会回滚
我会搜索API调用日志中的错误,如果你的最大ID是1099,那么下一次插入是1104,我敢说你肯定会在日志中找到4个错误,加上一个正确有效的插入。
请记住,序列并不是为了“看起来不错”,是的,如果所有的控制代码都通过了,那么当然,每个记录都是n + 1,它是“正确的”(从美学的Angular )插入。但是序列不是这样的。auto_increment只是确保你不会打破PK或UK约束。仅此而已。所以对于任何用法,不管是COMMIT还是ROLLBACK,序列都被“使用”。这是通过设计来保证数据完整性的。
为了模拟这种情况,您可以尝试一个自定义API调用(或本地插入,但如果您希望尽可能接近产品版本,您可以使用API调用),它总是在插入后回滚。然后检查auto_increment的当前序列值。

相关问题