我有一个中等大小的 MySQL 数据库,大约有 30 个表,其中一些是 1000 万条记录,一些是 1 亿条记录。将mysqldump
所有表(为独立的文件)的速度也相当快,也许需要20分钟。它会生成大约 15GB 的数据。最大的转储文件在 2GB 范围内。
当我将数据加载到另一个机器上的 MySQL 中时,它是一台六核 8GB 的机器,它需要永远。轻松 12 个时钟小时或更多。
我只是运行mysql客户端来加载文件,即
mysql database < footable.sql
Run Code Online (Sandbox Code Playgroud)
直接用mysqldump出来的文件
mysqldump database foo > footable.sql
Run Code Online (Sandbox Code Playgroud)
显然我做错了什么。我从哪里开始才能在合理的时间内完成?
我没有在转储或负载上使用任何开关。
Abd*_*naf 24
考虑这些要点,它们可能会在生成转储和恢复转储的情况下为您提供帮助。
Extended inserts
在转储中使用。--tab
格式以便您可以使用mysqlimport
,这比mysql < dumpfile
.innodb_flush_log_at_trx_commit = 2
在导入运行时暂时放入my.cnf。如果你需要 ACID,你可以把它放回 1试一试..
除了Abdul 的回答之外,我想强调该--disable-keys
选项的重要性,该选项会关闭键,直到为表加载了所有数据。此选项作为--opt
切换的一部分启用,默认情况下启用,但认为指出这一点很重要。
如果在插入过程中没有跳过键,那么插入的每一行都会重建索引。一个极其缓慢的过程。
小智 7
我最近一直在处理这个问题。您绝对可以通过并行导入来提高导入性能。大多数减速是基于 I/O,但您仍然可以通过转储到表中,然后一次导入 4 个来获得 40% 的改进。
你可以像这样使用 xargs 来做到这一点:
ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"
Run Code Online (Sandbox Code Playgroud)
在将文件推送到 mysql 之前对其进行 gzip 压缩并不会减慢任何速度,主要是因为降低了 I/O。我的表被压缩到大约 10:1,所以它节省了大量的磁盘空间。
我发现在 4 核机器上,使用 4 个进程是最佳的,虽然只比使用 3 个略好。如果你有 SSD 或快速 RAID,你可能会更好地扩展。
还有一些需要注意的地方。如果您有 4k 扇区驱动器,请确保您有key_cache_block_size=4096
和myisam_block_size=4K
.
如果您使用的是 MyISAM 表,请设置myisam_repair_threads = 2
或更高。这将允许您的额外核心帮助重建索引。
确保你根本没有交换。如果是,请减小innodb_buffer_pool_size
.
我想我也通过这些选项对 innnodb 进行了一些加速:
innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0
Run Code Online (Sandbox Code Playgroud)
(最后三个我没有广泛测试 - 我想我在互联网上找到了它们的建议。)请注意,这innodb_flush_log_at_commit=0
可能导致 mysql 崩溃或断电导致损坏。
如果您主要有 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
Run Code Online (Sandbox Code Playgroud)
2)为其设置全局值
SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;
Run Code Online (Sandbox Code Playgroud)
如果您没有权限全局设置bulk_insert_buffer_size,则执行此操作
service mysql restart
Run Code Online (Sandbox Code Playgroud)
当然,这不适用于 InnoDB。
换个角度看,不管表是InnoDB还是MyISAM,如果索引比表大,可能索引太多了。我通常猜测重新加载 MyISAM mysqldump 应该花费 mysqldump 生成时间的 3 倍。我还推测,重新加载 InnoDB mysqldump 所需的时间应该是 mysqldump 生成时间的 4 倍。
如果重新加载 mysqldump 的比例超过 4:1,那么您肯定会遇到以下两个问题之一:
您可以通过以下方式通过存储引擎测量数据的大小:
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;
Run Code Online (Sandbox Code Playgroud)
查看索引是否与数据一样大,甚至更大
你也可以考虑像这样禁用二进制日志:
echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql
Run Code Online (Sandbox Code Playgroud)
在重新加载脚本之前