抱歉,我看到过类似的帖子,但仍然找不到能解决我的问题的答案,而且我需要更多相关信息。
要求:创建现有数据库“db3”的精确副本“db4”。
遵循的程序:
- mysqldump -uuser -ppass db3 > db3.sql(大小为6G)
- mysql -uuser -ppass db4 < db3.sql(db4 是新创建的空白数据库)
第二步引发错误:
ERROR 1062 (23000) at line 5524: Duplicate entry '600806' for key 1"
我使用 --force 再次运行了第 2 步。恢复已完成,但还有另外 2 个类似的错误:
ERROR 1062 (23000) at line 6309: Duplicate entry '187694' for key 1
ERROR 1062 (23000) at line 6572: Duplicate entry '1567400' for key 1
完成后,当我查询 db4 数据库的某些表时,我能够看到丢失的记录。
问题:
这是否表示 db3 数据库已损坏/有问题?
如何继续创建 db3 的“一致/工作”副本(db4)?
谢谢,
答案1
出现此类“重复”的原因有多种:
- 你的数据已损坏。
- 应用程序使用自动增量进行 INSERT,但后来运行 UPDATE 手动将标识修改为不同的、可能存在的值。这种情况有时会发生在应用程序开发人员按“ID”排序并希望“修复排序”(实际上破坏一致性)时。
- 第二个问题的变体发生在人们在插入非唯一记录后添加“唯一”约束的时候。
错误消息确实涉及第一个键,在大多数数据库模式中,它是第一个值。查看原始转储输出,特别是 INSERT 语句,并检查
INSERT INTO ... values (0,...
扫描错误消息中给出的 mysql 转储的行号。
我期望的 mysqldump 类型的示例:
INSERT INTO foo (id,bar,baz) values (1,2,3);
INSERT INTO foo (id,bar,baz) values (0,4,5);
INSERT INTO foo (id,bar,baz) values (2,6,7);
在自动增量字段的“常规” INSERT 语句中,值“0”指定自动增量字段,因此不应显示在使用自动增量字段的数据库 SQL 转储中。通过 SQL 转储重新加载数据库,您的转储会要求 SQL 服务器将当前字段值增加一并插入该 ID。如果有人在插入记录后手动将标识更新为零,您的 MySQL 转储也会包含这个奇怪的 ID。
如果您将此转储重放到空表中,这将尝试创建以下记录:
1,2,3
2,4,5
2,6,7
由于“id”字段已设置为唯一自动增量,第二次 INSERT 将创建一个“错误”的记录(预期:0,4,5;实际:2,4,5),该记录与以下记录(id = 2)冲突,并因此给出错误消息。
类似地,有人“手动”将身份更新为已经存在的值,然后将记录更改为“唯一”。将记录类型更改为唯一不会使 MySQL 重新验证当前数据是否符合要求,因此会出现延迟错误。这种变体可能会创建如下转储:
INSERT INTO foo (id,bar,baz) values (1,2,3);
INSERT INTO foo (id,bar,baz) values (1,4,5);
INSERT INTO foo (id,bar,baz) values (2,6,7);
由于唯一性约束,尝试插入第二行将失败。
在这两种情况下,使用“--force”只会忽略“冲突”行并继续导入。“冲突”行将会丢失,但导致此冲突的行可能会存在(但带有错误的 ID 记录)。
如果我的想法符合您的问题,请检查您的数据库转储。如果是这样,以下是两种“使其工作”的解决方法:
导入数据分为两个步骤,首先只导入模式,然后导入数据。在导入数据之前,先从模式中删除唯一约束,然后再添加唯一约束(“ALTER TABLE ... add unique...”)。
强制导入架构和所有数据,导致“不同”约束问题。手动检查哪些记录是正确的,并将错误的记录重新分配给其原始值。
后续问题的示例:
mysql -uuser -ppass --execute "SET UNIQUE_CHECKS=0; source db3.sql" db4
这确实会强制导入所有冲突的记录,甚至违反任何实际的唯一约束。导入后,您将获得这三个记录(600806、187694 和 1567400)的多个条目,并且您必须通过检查转储来手动找出哪些是正确的,哪些“重复”确实导致了冲突,并手动将错误的记录“更新”为零(或转储中冲突行所说的任何内容)。
在这两种情况下,您的数据仍然违反了给定的架构:您的架构表明数据是唯一的,但事实并非如此。从长远来看,需要在应用程序级别修复数据。
答案2
首先,检查原始数据库中是否存在相关行。
很有可能发生了以下情况之一:
- 有问题的列/字段在某一时刻并不是唯一的,但后来被改变了。
- 这是您正在转储的从属数据库,在某些时候已经有一些 binlog 重播,并且插入了潜在的重复键
- 错误的 SQL 语句或命令导入导致重复的条目。
如果只有 3 行显示问题,请更正它们的关键字段,如果可能,请执行该实例的转储和导入,看看错误是否不会再次出现。我猜,它应该会消失。
答案3
前言
在我们的一台复制服务器陷入不一致状态后,我遇到了这个问题。我们无法通过快速修复使其恢复正常,因此决定使用新备份重新初始化复制。
上面提出的问题不是同一个问题,但确实返回了相同的错误,因此我决定添加这个答案,以防其他人正在寻找它。
这也是这个问题的完全重复DBA 堆栈交换但是因为这个问题在(我的)Google搜索结果中排名较高,所以我也将其发布在这里。
我们做了什么
我们用 MySQL Workbench 删除了实例上的所有数据库,我重新启动了实例并仔细检查了实例上是否没有剩余数据库。在主服务器上,我们已经开始用我们经常使用的脚本创建新的备份。
然后,一旦备份在故障服务器上,我们就开始导入,几个小时后它导入了大部分数据并因以下错误而失败:
ERROR 1062 (23000) at line XXX: Duplicate entry 'dbName-tblName' for key 'PRIMARY'
Operation failed with exitcode 1
我们想,好吧,也许在创建备份时出了点问题,我检查了备份中的数据,但没有发现任何问题。我们再次重试了所有步骤,以确保我们没有错过任何东西,但不幸的是,没有成功。
实际问题
显示的错误不是实际插入数据,而是创建索引。这就是为什么数据插入没有问题(我们检查过)但仍然产生错误的原因。显然删除所有表是不够的,索引数据仍然存在于服务器上(这可能是由于 MySQL 5.6 中的变化,因为我们以前从未遇到过这个问题)。而且由于这些索引的导入位于导入文件的中间某处,因此其余数据没有被导入。
修复
我们删除了 ibdata1 文件以及 mysql 数据库文件夹中的所有 innodb_index_stats 和 innodb_table_stats 文件,然后启动实例。然后 MySQL 会告诉你缺少一些系统表 您可以在此处找到更多相关信息
这解决了我们的问题并且我们的服务器现在正在按预期复制。
希望这可以为某个地方的某人节省一些时间:)