在我的 Django Web 应用程序中,我让用户删除了一些看起来可以安全删除的记录。事实证明,它们通过 ForeignKeyField
字段连接到相当大的一组其他非常重要的记录。我现在知道我可以管理删除的处理方式,但这种知识是在该事件发生之后出现的。
我的主要问题是:有没有一种简单的方法可以解决这个问题,或者只是从备份中小心翼翼地逐条恢复每条记录?
更多详情
每天晚上,我都会使用 mysqldump
备份 MySQL 数据库。所以我在这件事发生的前一天备份了所有数据。问题是这些备份文件将完整恢复数据库。鉴于我们在一周左右的时间里没有注意到这个问题,我认为恢复整个数据库不是一个选择,因为它会覆盖从删除发生之日到现在的其他合法更改。
我认为我唯一的选择是手动地从 MySQL 转储文件中一条一条地挑选记录,然后手动将它们INSERT
回 MySQL 数据库。这感觉像是一个坏主意,因为它很容易出现人为错误 - 我自己打字。
这是唯一的方法还是有更好的方法?!
最佳答案
我采取的方法是将备份恢复到不同的数据库。 (我们配置夜间 mysqldump 作业的方式,为每个数据库单独转储,并且转储文件中的 SQL 不包含对数据库名称的任何引用,因此我们很容易创建新数据库,例如
CREATE DATABASE restore_YYYYMMDD_dbname ;
然后将 gzipped mysqldump 运行到新的“恢复”数据库中:
gunzip -c dbname.backup_YYYMMDD.sql.gz | \
mysql u root -pSECRET -c --database restore_YYYYMMDD_dbname
显然,我们需要足够的磁盘空间,并且无论它启动多久,它都会启动。
然后我可以编写 SQL 来发现已删除的行。由于几乎每个表中都有一个唯一的 id 列作为主键,因此我们只需使用反连接来查找恢复表中当前数据库表中没有对应行的行
例如:
SELECT r.*
FROM restore_YYYYMMDD_dbname.mytable r
LEFT
JOIN dbname.mytable t
ON t.id = r.id
WHERE t.id IS NULL
我们可能不想恢复每一行,我们可以调整查询以向 WHERE 子句添加一些额外的谓词,以将其减少到我们实际想要的行。然后我们可以使用该查询作为 INSERT ... SELECT
INSERT INTO dbname.mytable
SELECT r.*
FROM ...
我们必须以正确的顺序处理每个表,这样我们就不会违反外键约束。 (如果我们确定我们知道自己在做什么,我们可以使用SET FOREIGN_KEY_CHECKS=0
;但以正确的顺序执行操作会更安全。
查找“已更改”的行比已删除的行稍微复杂一些,但我们可以做同样的事情,编写查询来完成此操作。
<小时/>我们的 mysqldump 进程设置方式非常简单。这仍然是一个手动过程,但我们让 SQL 为我们完成许多繁琐的工作。
如果您还没有测试过将数据库从 mysqldump 恢复到其他数据库,您可能需要首先在不同的环境中进行测试,这样您就不会无意中弄乱当前数据库。
关于mysql - Django - 有一个相当大的级联删除,现在我该如何解决这个问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30339041/