MySQL-如果删除了最后一行,则自动递增不会自动递增


8

我有一个表,其中包含一个自动递增的主键ID。如果我删除最后一行(最高ID,例如id = 6)并插入新行,则新ID从7开始。我必须更改哪个参数,使主键从6开始?

CREATE TABLE animals (
 id MEDIUMINT NOT NULL AUTO_INCREMENT,
 name CHAR(30) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=MyISAM;

INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');

结果:
id名称
1狗
2猫
3企鹅
4松懈
5鲸鱼
6鸵鸟

DELETE FROM animals WHERE id = 6;
INSERT INTO animals (name) VALUES
('x');

结果:
id名称
1狗
2猫
3企鹅
4松懈
5鲸鱼
7 x

谢谢你的建议。


那如果有差距怎么办?(这不仅可以通过删除行出现因其他一些原因,)
ypercubeᵀᴹ

如果插入后发生删除,您想怎么办?您要重用那些缺口吗?是的,那么我认为Identity对于该列而言不是正确的类型。它使您有机会不必担心该列中的唯一值。如果打算按顺序保留值,则可以只使用常规的INT / BIGINT类型的数据类型。为每个缺失的缺口查找/重用/重置值就像丧失了身份财产的目的。
Anup Shah 2013年

@giordano为什么要成为AUTO_INCREMENT PRIMARY KEY简洁的人?对付它也有一个“缺口”在表中的数据,如果你更新/删除因碎片..
雷蒙德Nijland

不久前,我对SQL Server的连续auto_increment值进行了调查:sqlity.net/en/792/the-gap-in-identity-value-sequence-尽管不是MySQL的,但其基本机制是相同的,因此您将获得类似的结果。简而言之,您无法防止自动生成的序列出现缺口。
塞巴斯蒂安·梅恩

@ypercube:感谢您的回答。确实,我从另一个更复杂的示例中获得了差距,但我想展示一个最小的示例。真实的示例是(1)由于属性的更改而更改了行的到期日期(例如,从产品表中删除),并且(2)添加具有相同产品代码,新的属性,新的生效日期和未到期的新产品日期。发生的是新的主键并没有自动增加+1而是+2。显然,在步骤(1)或(2)中有一个不可见的自动增量。我想知道造成差距的其他原因是什么。
giordano

Answers:


12

这是设计使然-所有DBMS都使用自动增量列来执行此操作。

如果不这样做,则可能会损坏外部参照完整性。举一个简单的例子,假设您正在使用自动增量列作为键来存储用于缩短服务的URL。您不知道是否已将缩短的URL分配给任何人,并且数据库当然也没有提供,因此重复使用ID 1234可能导致某人的可怜的老太在单击http:/时访问somenastypornsite.xxx而不是loverlyknitting.org。/shortthi.ng/1234,而不是显示“抱歉,但我们的记录中不再存在此链接”消息。

另外,如果您在删除最后一个项目后重设增量,那么在删除第5个项目后,您是否还会进行所有对5,000,000个第5个项目之后的所有内容重新编号的工作(或期望数据库进行重新编号)?完成对其他表的更改,其中其他表的外键约束指向增量列?这样的额外工作可能会使IO变得非常昂贵。

如果在删除最后一项后确实重置了增量点,请非常小心您的事务隔离级别:您可能会在另一个事务使用该值时重置它,从而导致错误(或更糟糕的是,无提示失败),除非您要确保完全100%隔离行动。

我通常建议使用数据库的人员阅读“ SQL Antipatterns”,其中有一个关于此问题的章节名为“ Psuedo-Key Neat Freaks”(以比章节标题所暗示的方式友好的方式涵盖了此问题!)。本质上,如果值的含义不只是键(或最多带有插入顺序的信息),则它可能不应该是自动递增的列,并且如果值不是键(或最多带有插入顺序的含义)也没有意义。信息),那么差距就无关紧要。


感谢您的解释。我看到我必须深入了解关键概念。我不知道自动递增机制是如何工作的,因为当我没有删除但更改(更新)一行并添加新行时,我还观察到了主键中的间隙。绝对,我不会做的是手动更改自动增量值。
giordano

关于“深入研究关键概念”,我强烈推荐Bill Karwin撰写的《 SQL Antipatterns》一书-它涵盖了本主题以及其他一些常见(但不太常见)主题,讨论了如何解决错误以及为什么常见错误方法可能会导致问题,如何解决问题,以及何时以简洁但可访问的方式可以使用(或唯一的选择)“错误的”方法。
David Spillett

Spillet:感谢您的表示。我现在阅读,这非常有帮助。然而,我不明白为什么InnoDB和MyISAM的计数方式不同:dba.stackexchange.com/questions/51883/…–
giordano

0

您可以使用以下方法重置auto_increment值:

ALTER TABLE MyTable AUTO_INCREMENT = 1234;

您需要确定表中存在的最大值,并将该值加1以在上面的语句中使用。


一个坏主意,这将锁定您的表以防止在“几乎所有” MySQL版本中进行读取或写入。MySQL 5.6可以进行实时更改,但有时还需要锁定表。
雷蒙德·尼兰

2
@RaymondNijland我认为锁不会持续足够长的时间让任何人注意到。
ypercubeᵀᴹ

@ Max,Raymond,ypercube:感谢您的回答。我将避免进行此类更改。
giordano
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.