从mysqldump加载数据的速度较慢


21

我有一个中等大小的MySQL数据库,其中包含大约30个表,其中一些是1000万条记录,大约是1亿条。将mysqldump所有表(为独立的文件)的速度也相当快,也许需要20分钟。它产生约15GB的数据。最大的转储文件在2GB范围内。

当我将数据加载到另一台6核8GB机器上的MySQL中时,这将花费很多时间。轻松12个时钟小时或更长时间。

我只是运行mysql客户端来加载文件,即

mysql database < footable.sql

直接与文件直接从mysqldump中移出

mysqldump database foo > footable.sql

显然我做错了。我从哪里开始,以便可以在合理的时间内完成?

我没有在转储或负载上使用任何开关。


您还可以在转储负荷期间desactivate的二进制日志
塞德里克PEINTRE

Answers:


22

请考虑以下几点,以防生成转储并将其还原。

  1. Extended inserts在转储中使用。
  2. 转储带有--tab格式的文件,以便您可以使用它mysqlimport,它比mysql < dumpfile
  3. 导入有多个线程,每个线程一个。
  4. 如果可能,请使用其他数据库引擎。导入到像innodb这样的高事务性引擎中非常慢。插入到MyISAM这样的非事务引擎中要快得多。
  5. 关闭外键检查并打开自动提交。
  6. 如果要导入innodb,那么最有效的方法就是innodb_flush_log_at_trx_commit = 2在导入运行时暂时将my.cnf 放入。如果需要ACID,可以将其放回1

试试看..


您的提示innodb_flush_log_at_trx_commit = 2挽救了我的生活。导入600 MB转储(作为一个大交易)将需要6个小时,但是使用此临时设置,它可以在30分钟内完成!
Daniel Marschall

1
您想要知道的事,然后在尝试按“ enter”后四天从转储中加载80gig数据库... :)
Dmitri DB

7

除了Abdul的答案外,我还要强调该--disable-keys选项的重要性,该选项会关闭键,直到为表加载所有数据为止。此选项作为--opt切换的一部分启用,默认情况下已启用,但指出这一点很重要。

如果在插入过程中不跳过键,则插入的每一行都将重建索引。一个极其缓慢的过程。


--disable-keys是mysqldump的一部分吗?还是重装?
Pat Farrell '02

它会在转储文件被添加
德里克·唐尼

--opt默认情况下
处于启用状态

1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
伊桑·艾伦

7

最近我已经处理了很多。您绝对可以通过并行导入来提高导入性能。大部分的减速都是基于I / O的,但是仍然可以通过转储到表中然后一次导入4来获得40%的改进。

您可以使用xargs做到这一点:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

在将文件推送到mysql之前将文件压缩一下不会降低任何速度,这主要是因为I / O降低了。我的表被压缩到大约10:1,因此节省了大量磁盘空间。

我发现在4台核心计算机上,使用4个进程是最佳的,尽管仅比使用3个进程略好。如果您具有SSD或快速RAID,则扩展性可能会更好。

其他一些注意事项。如果您具有4k扇区驱动器,请确保具有key_cache_block_size=4096myisam_block_size=4K

如果使用MyISAM表,请设置myisam_repair_threads = 2或更高。这将使您的额外核心可以帮助重建索引。

确保您根本没有交换。如果是这样,请减小的大小innodb_buffer_pool_size

我想通过这些选项我也可以使用innonodb进行加速:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(最后三个我没有进行广泛的测试-我认为我是在互联网上作为建议来找到它们的。)请注意,这样做innodb_flush_log_at_commit=0可能会导致mysql崩溃或断电而损坏。


Greg,欢迎您访问该网站,并感谢您的回答。你能否提供一些资料和理由:在您的建议*_block_sizemyisam_repair_threads?此外,不确定我们是否应基于“来自互联网的建议”来建议您调整变量:)
Derek Downey

5

如果您主要有MyISAM表,则应增加大容量插入缓冲区。这是MySQL文档关于设置bulk_insert_buffer_size的内容

MyISAM使用特殊的树状缓存,以在向非空添加数据时更快地执行INSERT ... SELECT,INSERT ... VALUES(...),(...),...和LOAD DATA INFILE的批量插入表。此变量限制每个线程中缓存树的大小(以字节为单位)。将其设置为0将禁用此优化。默认值为8MB。

您需要做两件事

1)将其添加到/etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2)为其设置全局值

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

如果您没有权限全局设置bulk_insert_buffer_size,请执行此操作

service mysql restart

当然,这不适用于InnoDB。

从另一个角度来看,无论表是InnoDB还是MyISAM,如果索引大于表,则索引可能过多。我通常认为,重新加载MyISAM mysqldump所需的时间应该是mysqldump生成时间的3倍。我还希望一个InnoDB mysqldump的重装时间应该是mysqldump制作时间的4倍。

如果您超过了4:1的比例来重新加载mysqldump,则肯定存在以下两个问题之一:

  • 索引过多
  • 由于列大,索引太大

您可以使用以下存储引擎来衡量数据的大小:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

查看索引是否几乎与数据一样大甚至更大

您也可以考虑禁用二进制日志记录,如下所示:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

重新加载脚本之前


我不知道您保存了多少天,但确实已经很多了
Dmitri DB

2

如果您完全绕开文件系统,而只是将mysqldump的输出直接传递到MySQL进程中,则应该会看到明显的性能改进。最终多少取决于您使用的磁盘驱动器的类型,但是仅出于这个原因,无论数据库大小如何,我都很少使用转储文件。

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy

1

根据我的经验,硬盘是瓶颈。忘记旋转磁盘。SSD更好,但到目前为止最好的方法是在RAM中执行此操作-如果您有足够的时间来保存整个数据库一小段时间。大致:

  1. 停止mysqld
  2. 移走/ var / lib / mysql的现有内容
  3. 创建一个空的/ var / lib / mysql目录
  4. 挂载-t tmpfs -o size = 32g tmpfs / var / lib / mysql(调整大小)
  5. 创建一个空的数据库(例如mysql_install_db或恢复以前的内容)
  6. 启动mysqld
  7. 进口
  8. 停止mysqld
  9. 复制/ var / lib / mysql到mysql2
  10. umount mysql; rmdir MySQL
  11. 将mysql2移至mysql
  12. 启动mysqld,开心一点

对我来说,可以在大约35分钟(mydumper / myloader),45分钟(mysqldump --tab / mysqlimport),50分钟(mysqldump / mysql)中导入约10G(/ var / lib / mysql消耗约20G)的转储。 ,在2x6核3.2GHz Xeon上。

如果一台计算机上没有足够的RAM,但是几台计算机彼此相邻且具有快速的网络,那么看看它们的RAM是否可以与nbd(网络块设备)结合起来就很有趣。或者,使用innodb_file_per_table,您可能可以对每个表重复上述过程。


出于好奇,我尝试将mysql数据目录存储在RAM中,以将其与2 GB数据库的SSD(对于那些感兴趣的人为SSDSC2BB48)进行比较。结果是相同的,两者都花费了207-209秒。考虑到您还必须启动/停止mysql并复制目录的事实,在我的情况下,使用RAM磁盘而不是SSD慢得多
Shocker

如果您花了大约3-4分钟的时间,那么我想您的数据库要比该主题的要小得多。听到与本主题中提到的数据库类似的大型数据库的经验,会很有趣。
egmont
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.