在我的Django Web应用程序中,我让用户删除了一些似乎可以删除的记录。事实证明,他们通过ForeignKeyField
字段连接到一大堆其他非常重要的记录。我现在知道我可以管理如何处理删除,但是在发生此事件之后 。
我的主要问题是:是否有一种简单的方法可以解决这个问题,还是仅仅是从备份中逐一恢复每条记录的问题?
更多详情
每天晚上,我使用mysqldump
备份MySQL数据库。所以我在发生这一天的前一天备份了所有数据。问题是这些备份文件将在完整中恢复数据库。鉴于我们在一周左右没有注意到这个问题,我认为恢复整个数据库不是一个选择,因为它会从删除发生的那天起覆盖其他合法的更改。
我认为我唯一的选择是逐个手动从MySQL转储文件中挑选记录,然后手动INSERT
将它们重新导入MySQL数据库。这感觉是一个坏主意,因为它很容易出现人为错误 - 我自己打字。
这是唯一的方式还是有更好的方法?!
答案 0 :(得分:1)
我将采用的方法是将备份还原到不同的数据库。 (我们配置每晚mysqldump作业的方式,每个数据库的单独转储,以及转储文件中的SQL不包含对数据库名称的任何引用,因此我们很容易创建新数据库,例如
CREATE DATABASE restore_YYYYMMDD_dbname ;
然后将gzip压缩的mysqldump运行到新的“恢复”数据库中:
gunzip -c dbname.backup_YYYMMDD.sql.gz | \
mysql u root -pSECRET -c --database restore_YYYYMMDD_dbname
显然,我们需要足够的磁盘空间,无论它曲柄多长,它都会发动。
然后我可以编写SQL来发现已删除的行。由于我们在几乎每个表中都有一个唯一的id
列作为PRIMARY KEY,我们只使用反连接来查找已恢复表中当前数据库表中没有相应行的行
例如:
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还原到其他数据库,您可能希望先在不同的环境中对其进行测试,这样您就不会无意中弄乱当前的数据库。