Rya*_*yan 5 mysql innodb duplication unique-constraint mysql-5.7
我正在auto-increment向大表中添加一个字段。
该字段已填充(大约 1-500M)并且新插入的内容正在正确地手动递增。为了验证,我运行了一个查询以显示任何重复项:
mysql> SELECT new_id, COUNT(*) AS count FROM my_table GROUP BY new_id HAVING count > 1;
# No Results
Run Code Online (Sandbox Code Playgroud)
当我手动查看最新记录时,我会看到看起来像自动递增的BIGINT(20)字段。NULL该列中不存在 's 。
然而,当我尝试将索引更改为 a UNIQUE INDEX(从非唯一索引,但具有唯一值)时,它会触发DUPLICATE KEY错误。并且重复键始终为MAX(new_id)+1,因此有问题的重复项的aSELECT始终不返回任何结果。
这是我正在运行的内容:
mysql> SELECT MAX(new_id) FROM my_table;
+-------------+
| MAX(new_id) |
| 512345678 |
+-------------+
1 row in set (0.00 sec)
mysql> ALTER TABLE my_table
DROP INDEX `idx_new_id`,
ADD UNIQUE INDEX `idx_new_id ` USING BTREE (`new_id `);
ERROR 1062 (23000): Duplicate entry '512345679' for key 'idx_new_id'
Run Code Online (Sandbox Code Playgroud)
但为什么?这个记录根本不存在!该MAX是少1比这和因为查询之前并没有改变。所以我证明...
mysql> SELECT MAX(new_id) FROM my_table;
+-------------+
| MAX(new_id) |
| 512345678 |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM my_table WHERE new_id = 512345679;
# No results
Run Code Online (Sandbox Code Playgroud)
512345679如果记录512345679甚至不存在,为什么 MySQL 会标记为重复?
你能指出我接下来要看的地方吗?
最终,我打算将主键从另一个字段更改为这个字段。但是我试图通过预先填充唯一 ID(已经完成)来防止停机。如果我在这一步成功,我会将这个new_id字段切换到PRIMARY KEY和AUTOINCREMENT它。
这是SHOW CREATEfor my_table:
CREATE TABLE `my_table` (
`new_id` bigint(20) NOT NULL,
`id` bigint(20) NOT NULL,
`username` varchar(80) NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_username` (`username `),
KEY `idx_new_id` (`new_id`) USING BTREE,
KEY `idx_id` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Run Code Online (Sandbox Code Playgroud)
我尝试在 MacOS 的 MySQL 5.7.12 中运行你的代码。我似乎无法复制这个,但我发现了一些有趣的东西。
SQL-Fiddle 有 MySQL 5.7.17。MySQL 5.7.13 中出现错误。这些版本之间是否修复了有关删除和添加二级索引的问题?我相信是的。请注意5.7.14 的发行说明,小标题下的要点 21Bugs Fixed:
InnoDB:在回滚删除并添加辅助索引的 ALTER TABLE 操作期间引发断言。(错误#22005726)
问:什么是二级索引?根据MySQL 文档,Clustered and Secondary Indexes标题为“二级索引如何与聚集索引相关”:
除聚集索引外的所有索引都称为二级索引。在 InnoDB 中,辅助索引中的每条记录都包含该行的主键列,以及为辅助索引指定的列。InnoDB 使用此主键值来搜索聚集索引中的行。
这表明aUNIQUE INDEX只是一个二级索引。二级索引会将主键的副本附加到每个索引条目。
我的断言是,当涉及到同时在同一列上删除和创建索引时,5.7.13 中引入了一个 5.7.12 中不存在的错误。
回头看看你的ALTER TABLE命令
mysql> ALTER TABLE my_table
DROP INDEX `idx_new_id`,
ADD UNIQUE INDEX `idx_new_id` USING BTREE (`new_id `);
Run Code Online (Sandbox Code Playgroud)
您删除了具有特定索引名称 ( idx_new_id) 和特定列列表(仅一列new_id)的索引,然后添加一个具有相同名称和相同列列表的新索引,但将其设为索引UNIQUE。最终效果是索引从未真正被删除,并且UNIQUE属性只是附加到已经存在的非唯一索引。然后,在幕后,mysqld 尝试将数据加载到已填充的表和仍填充的索引中,从而创建重复键错误。请注意,我只是断言这一点。我必须查看 5.7.13 的源代码,看看这是否确实发生。
尽管如此,5.7.12 和 5.7.14 无法重现此问题。这表明这个奇怪的情况在制作 5.7.14 时已得到解决。
根据我的所有猜测,以下是我的建议:
建议#1:升级到 5.7.14 或更高版本
建议#2:更改ALTER TABLE为使用不同的索引名称
mysql> ALTER TABLE my_table
DROP INDEX `idx_new_id`,
ADD UNIQUE INDEX `uniq_idx_new_id` USING BTREE (`new_id`);
Run Code Online (Sandbox Code Playgroud)
建议#3:执行 2 个ALTER TABLE命令
mysql> ALTER TABLE my_table DROP INDEX `idx_new_id`;
mysql> ALTER TABLE my_table ADD UNIQUE INDEX `uniq_idx_new_id` USING BTREE (`new_id`);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3597 次 |
| 最近记录: |