Django - 有一个体面大小的级联删除,现在我该如何解决这个问题?
Django - There was a decent size cascade delete, now how do I fix this?
在我的 Django Web 应用程序中,我让用户删除了一些看起来可以安全删除的记录。事实证明,它们通过 ForeignKeyField
字段连接到相当大的其他非常重要的记录集。我现在知道我可以管理如何处理删除,但这个知识是在 这个事件发生之后。
我的主要问题是:有没有一种简单的方法可以解决这个问题,还是只需从备份中逐条小心地恢复每条记录?
更多详情
每天晚上,我都会使用 mysqldump
备份 MySQL 数据库。所以我在这件事发生的前一天备份了所有数据。问题是这些备份文件将在 完整 中恢复数据库。鉴于我们在一周左右的时间里没有注意到这个问题,我认为恢复整个数据库不是一种选择,因为它会覆盖从删除发生之日到现在的其他合法更改。
我认为我唯一的选择是手动,一条一条,从MySQL转储文件中挑选出记录,然后手动INSERT
它们回到 MySQL 数据库。这感觉像是个坏主意,因为它很容易出现人为错误——我自己打字。
这是唯一的方法还是有更好的方法?!
我将采用的方法是将备份还原到不同的 数据库。 (我们配置每晚 mysqldump 作业的方式,为每个数据库单独转储,转储文件中的 SQL 不包含对数据库名称的任何引用,因此我们很容易创建新数据库,例如
CREATE DATABASE restore_YYYYMMDD_dbname ;
然后 运行 将 mysqldump 压缩到新的 "restore" 数据库中:
gunzip -c dbname.backup_YYYMMDD.sql.gz | \
mysql u root -pSECRET -c --database restore_YYYYMMDD_dbname
显然,我们需要足够的磁盘 space,无论它启动多长时间,它都会启动。
然后我可以写SQL来发现删除的行。由于我们在几乎每个 table 中都有一个唯一的 id
列作为主键,我们只需使用反连接来查找恢复的 table 中没有对应行的行在当前数据库中 table
例如:
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 ...
我们必须按正确的顺序执行每个 table,这样我们就不会违反外键约束。 (我们可以使用 SET FOREIGN_KEY_CHECKS=0
,如果我们确定我们知道我们在做什么;但以正确的顺序执行操作更安全。
查找 "changed" 行比删除行稍微复杂一些,但我们可以做同样的事情,也可以编写查询来做到这一点。
我们设置 mysqldump 进程的方式非常简单。这仍然是一个手动过程,但我们让 SQL 为我们完成了很多繁琐的工作。
如果您还没有测试过将数据库从 mysqldump 恢复到其他数据库,您可能想先在不同的环境中进行测试,以免无意中弄乱当前数据库。
在我的 Django Web 应用程序中,我让用户删除了一些看起来可以安全删除的记录。事实证明,它们通过 ForeignKeyField
字段连接到相当大的其他非常重要的记录集。我现在知道我可以管理如何处理删除,但这个知识是在 这个事件发生之后。
我的主要问题是:有没有一种简单的方法可以解决这个问题,还是只需从备份中逐条小心地恢复每条记录?
更多详情
每天晚上,我都会使用 mysqldump
备份 MySQL 数据库。所以我在这件事发生的前一天备份了所有数据。问题是这些备份文件将在 完整 中恢复数据库。鉴于我们在一周左右的时间里没有注意到这个问题,我认为恢复整个数据库不是一种选择,因为它会覆盖从删除发生之日到现在的其他合法更改。
我认为我唯一的选择是手动,一条一条,从MySQL转储文件中挑选出记录,然后手动INSERT
它们回到 MySQL 数据库。这感觉像是个坏主意,因为它很容易出现人为错误——我自己打字。
这是唯一的方法还是有更好的方法?!
我将采用的方法是将备份还原到不同的 数据库。 (我们配置每晚 mysqldump 作业的方式,为每个数据库单独转储,转储文件中的 SQL 不包含对数据库名称的任何引用,因此我们很容易创建新数据库,例如
CREATE DATABASE restore_YYYYMMDD_dbname ;
然后 运行 将 mysqldump 压缩到新的 "restore" 数据库中:
gunzip -c dbname.backup_YYYMMDD.sql.gz | \
mysql u root -pSECRET -c --database restore_YYYYMMDD_dbname
显然,我们需要足够的磁盘 space,无论它启动多长时间,它都会启动。
然后我可以写SQL来发现删除的行。由于我们在几乎每个 table 中都有一个唯一的 id
列作为主键,我们只需使用反连接来查找恢复的 table 中没有对应行的行在当前数据库中 table
例如:
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 ...
我们必须按正确的顺序执行每个 table,这样我们就不会违反外键约束。 (我们可以使用 SET FOREIGN_KEY_CHECKS=0
,如果我们确定我们知道我们在做什么;但以正确的顺序执行操作更安全。
查找 "changed" 行比删除行稍微复杂一些,但我们可以做同样的事情,也可以编写查询来做到这一点。
我们设置 mysqldump 进程的方式非常简单。这仍然是一个手动过程,但我们让 SQL 为我们完成了很多繁琐的工作。
如果您还没有测试过将数据库从 mysqldump 恢复到其他数据库,您可能想先在不同的环境中进行测试,以免无意中弄乱当前数据库。