当DDL同时使用时,如何使用mysqldump和单事务获取正确的转储?

时间:2009-01-16 18:10:50

标签: mysql mysqldump corruption

我是MySQL的新手,我正在找出使用mysqldump执行在线热逻辑备份的最佳方法。 This page建议使用此命令行:

mysqldump --single-transaction --flush-logs --master-data=2
          --all-databases > backup_sunday_1_PM.sql

但是......如果您仔细阅读文档you find that

  

正在进行--single-transaction转储,以确保有效的转储文件   (正确的表格内容和二进制日志位置),不应使用其他连接   以下陈述:ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE。一个   一致读取不会与这些语句隔离,因此在表上使用它们   被转储可能导致SELECT执行的mysqldump检索表内容   获取不正确的内容或失败。

那么,有没有办法防止这种可能的转储损坏情况? 即一个可以暂时阻止这些语句的命令。

PS:关于此主题http://bugs.mysql.com/bug.php?id=27850

的MySQL错误输入

3 个答案:

答案 0 :(得分:8)

打开mysql命令窗口并发出以下命令:

mysql> FLUSH TABLES WITH READ LOCK;

这将锁定此MySQL实例上所有数据库中的所有表,直到您发出UNLOCK TABLES(或终止包含这些读锁的客户端连接)。

要确认这一点,您可以打开另一个命令窗口并尝试执行ALTERDROPRENAMETRUNCATE。这些命令挂起,等待释放读锁定。按Ctrl-C终止等待。

但是当表格具有读锁定功能时,您仍然可以执行mysqldump备份。

FLUSH TABLES WITH READ LOCK命令可能与使用--lock-all-tables的{​​{1}}选项相同。这并不完全清楚,但this doc似乎支持它:

  

UNLOCK TABLES的另一个用途是   释放获得的全局读锁   带有读锁的FLUSH表。

mysqldumpFLUSH TABLES WITH READ LOCK都使用“全局读锁定”这一短语,所以我认为它们可能会做同样的事情。因此,您应该能够将该选项用于--lock-all-tables并防止并发ALTER,DROP,RENAME和TRUNCATE。


重新。您的评论:以下内容来自您链接到的MySQL错误日志中的Guilhem Bichot:

  

您好。 --lock-all-tables调用FLUSH   带读锁的表格。就这样吧   预计会阻止ALTER,DROP,RENAME,   或TRUNCATE(除非有错误或   我错了)。但是, - lock-all-tables   --single-transaction无法正常工作(mysqldump抛出错误信息):   因为lock-all-tables会锁定所有   服务器的表格反对写入   在备份期间,   而单一交易是有意的   让备份期间发生写入   (通过使用一致读取SELECT   一个交易),它们是不相容的   在性质上。

从这一点来看,听起来你不能在备份期间获得并发访问,同时阻止ALTER,DROP,RENAME和TRUNCATE。

答案 1 :(得分:2)

我认为阅读文档的这一部分同样如此,我发现了更多信息:

4.5.4。 mysqldump - 数据库备份程序 http://dev.mysql.com/doc/en/mysqldump.html

  

对于InnoDB表,mysqldump提供了一种在线方式   备份

shell> mysqldump --all-databases --single-transaction > all_databases.sql
     

此备份获取所有表的全局读锁(使用FLUSH   在转储开始时使用READ LOCK表格。一旦这个   已获取锁定,读取二进制日志坐标和   锁被释放。如果长时间更新语句正在运行时   发出FLUSH语句后,MySQL服务器可能会停滞不前   那些陈述结束了。之后,转储变得无锁   不会干扰表上的读写操作。如果更新   MySQL服务器收到的语句很短(就...而言)   执行时间),初始锁定期不应该明显,   即使有很多更新。

--opt--single-transaction选项存在冲突:

  

- 选择

     

此选项是速记。它与指定相同   --add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset。它应该为您提供快速转储操作并生成可以重新加载的转储文件   快速进入MySQL服务器。

     

默认情况下启用--opt选项。使用--skip-opt禁用它。

如果我正确理解您的问题,您需要将实际数据和DDL(数据定义语言)放在一起,因为如果您只想要DDL,则可以使用--no-data。有关这方面的更多信息,请访问:

http://dev.mysql.com/doc/workbench/en/wb-reverse-engineer-create-script.html

  

如果要创建,请使用mysqldump的--databases选项   数据库及其所有对象。如果没有CREATE DATABASE   脚本文件中的db_name语句必须导入数据库   对象到现有模式中,或者如果没有模式,则为新模式   创建了未命名的架构。

根据The Definitive Guide to MySQL 5 By Michael Kofler的建议,我建议使用以下选项:

--skip-opt
--single-transaction
--add-drop-table
--create-options
--quick
--extended-insert
--set-charset
--disable-keys

此外,未提及的是--order-by-primary 此外,如果您使用--databases选项,则还应使用--add-drop-database,尤其是与此answer结合使用时如果要备份连接在不同网络上的数据库,则可能需要使用--compress选项。

所以mysqldump命令(不使用--compress--databases--add-drop-database选项)将是:

mysqldump --skip-opt --order-by-primary --single-transaction --add-drop-table --create-options --quick --extended-insert --set-charset -h db_host -u username --password="myPassword" db_name | mysql --host=other_host db_name

我删除了本书中给出的--disable-keys的引用,因为我理解它对InnoDB无效。 MySql manual州:

  

对于每个表,使用/ *!40000 ALTER包围INSERT语句   表tbl_name DISABLE KEYS /;和/ !40000 ALTER TABLE tbl_name   ENABLE KEYS * /;声明。这样可以更快地加载转储文件   因为索引是在插入所有行之后创建的。这个   option仅对MyISAM表的非唯一索引有效。

我还发现了这个错误报告http://bugs.mysql.com/bug.php?id=64309,它在Paul DuBois who also wrote a few books的底部有评论,除​​了在该错误报告中发现的评论之外,我没有参考这个特定问题。

现在要创建“终极备份”,我建议考虑一下这个shell脚本的内容

  1. https://github.com/red-ant/mysql-svn-backup/blob/master/mysql-svn.sh

答案 2 :(得分:1)

如果没有锁定表,则无法获得一致的转储。我只是在一天的时间里做我的,没有注意到2分钟的转储。

一种解决方案是进行复制,然后备份从站而不是主站。如果从站在备份期间未命中写入,它将在稍后赶上。如果主服务器出现故障,这也将为您提供实时备份服务器。哪个好。