【问题标题】:How dump partial backup from large MySql database?如何从大型 MySql 数据库中转储部分备份?
【发布时间】:2020-01-31 11:51:48
【问题描述】:

这个话题非常关键,因为也许没有确切的答案。我在生产环境中有一个 22Gb MySql 数据库。但出于测试目的,我需要从数据库中提取例如 2Gb,并且此提取必须具有所有依赖项(键、索引、FK 等)。如何在 MySql 数据库中执行此部分提取?

【问题讨论】:

  • 只能“手动”。转储结构(无数据)并恢复到新数据库。使用INSERT INTO new_db.root_table TABLE old_db.root_table LIMIT xxx 将一些(不是全部)记录复制到根表。然后使用INSERT IGNORE 复制依赖表 - 只有那些与复制到新根表相关的记录才会被复制。然后备份这个新数据库并在另一台服务器上恢复。 PS。如果存在某些触发器,则必须在复制所有数据后恢复它们。
  • @Akina 嗨。感谢您的回答并理解问题所在。但是此时一个有大量的表并且将很难“手动”使用这种策略。现在我将尝试另一种形式来提取数据,如果我没有得到另一种方法,我会尝试你的策略。非常感谢您的回复。
  • 有大量表格,“手动”使用这种策略会非常困难 为什么?从 INFORMATION_SCHEMA 获取数据库中所有外键的父子数据并构建正确排序的表列表(此外,如果您添加 level 字段,递归 CTE 将自动完成)。
  • @Akina 嗨。谢谢你的回复。事实是我没有数据库技能来执行您解释的内容。我怎样才能获得这样做的教程?对于临时解决,我使用“head -n 5000 > temp.sql”从 sql 导出数据中获得 5000 行第一行。使用这个临时文件,我将填充数据库。但我知道这是错误的方式!!!

标签: mysql database mysql-workbench database-restore


【解决方案1】:

此查询从指定数据库中选择所有表名,并在外键树中显示它们的级别。

WITH RECURSIVE
cte1 AS 
(
SELECT table_name, 
       referenced_table_name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE table_schema = 'test'
  AND referenced_column_name IS NOT NULL
),
cte2 AS
(
SELECT t1.referenced_table_name name, 1 level
FROM cte1 t1
WHERE NOT EXISTS ( 
                 SELECT NULL
                 FROM cte1 t2
                 WHERE t1.referenced_table_name = t2.table_name
                 )
UNION ALL
SELECT cte1.table_name, cte2.level + 1
FROM cte1 
JOIN cte2 ON cte1.referenced_table_name = cte2.name
WHERE cte2.level <= (
                    SELECT COUNT(*)
                    FROM cte1
                    )
)
SELECT name, MIN(level) level
FROM cte2
GROUP BY name
ORDER BY name, level;

当您重新创建数据库结构或将数据从原始数据库复制到重新创建的副本时,您必须按所示顺序处理表。

当你删除表时,你必须按倒序进行。

正常状态下最大level值不能超过表数。但是数据库结构中可能存在引用环。在这种情况下,最大level 值将大于表的数量,并且整个技术不适用


在您的特定情况下,您:

  1. 执行此查询(不要忘记将WHERE table_schema = 'test' 替换为您的实际数据库名称)。
  2. 创建新数据库。
  3. 对于输出中的每一行(存储顺序)执行命令
CREATE TABLE new_database.{name} LIKE old_database.{name} ;
  1. 对于输出中level = 1 执行命令的每一行
INSERT INTO new_database.{name} 
SELECT * FROM old_database.{name} LIMIT {some_value};

some_value 对于所有根表或个人可能都相同。

  1. 对于输出中level &gt; 1 执行命令的每一行
INSERT IGNORE INTO new_database.{name} 
SELECT * FROM old_database.{name} LIMIT {some_value};
  1. 享受吧。

如果方案包含触发器,则它们必须单独备份并作为最后一步恢复到新数据库中。

【讨论】:

  • Akina,你好。我花了一段时间才明白一切是如何运作的。我已经和我的团队将处理的结果投入生产。我将更多地研究数据库的这些方面。它工作得非常好。感谢您一步一步。
【解决方案2】:

使用 Jailer,您可以将数据导出到 SQL 脚本,该脚本可以遍历外键约束以包含维护参照完整性所需的所有数据。

https://github.com/Wisser/Jailer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2016-02-19
    相关资源
    最近更新 更多