我正在尝试导入一个由mysqldump为InnoDB表生成的大型SQL文件,但是即使在my.cnf中调整了一些参数并禁用了AUTOCOMMIT(以及FOREIGN_KEY_CHECKS和UNIQUE_CHECKS之后,也要花很长时间),该表没有任何外键或唯一键)。但是我想知道是否由于表中的多个索引花费了这么长时间?
看一下SQL文件,似乎在插入所有数据之前正在CREATE TABLE语句中创建索引。根据我的(limited) research和个人经验,我发现插入所有数据后添加索引的速度更快。是否不必检查每个INSERT的索引?我知道mysqldump确实有一个--disable-keys
选项,它确实可以做到这一点–在插入之前禁用键,但是显然,这仅适用于MyISAM表,而不适用于InnoDB。
但是,为什么mysqldump不能在InnoDB表的CREATE TABLE语句中不包含键,然后在插入所有数据之后执行ALTER TABLE?还是InnoDB的工作方式不同,并且速度没有差异?
谢谢!
答案 0 :(得分:3)
我在过去的工作中对这个概念进行了一些试验,我们需要一种在MySQL服务器之间复制架构的快速方法。
当您插入具有二级索引的表时,确实存在性能开销。插入需要更新聚簇索引(又名表),也需要更新二级索引。表具有的索引越多,插入的开销就越大。
InnoDB具有称为change buffer的功能,该功能可以通过延迟索引更新来有所帮助,但最终必须将它们合并。
插入没有二级索引的表的速度更快,因此很容易尝试将索引的创建推迟到数据加载之后再进行。
Percona Server(MySQL的一个分支)尝试使用mysqldump --optimize-keys
选项。当您使用此选项时,它将更改mysqldump的输出,使其具有不带索引的CREATE TABLE,然后插入所有数据,然后在数据加载后插入ALTER TABLE以添加索引。参见https://www.percona.com/doc/percona-server/LATEST/management/innodb_expanded_fast_index_creation.html
但是根据我的经验,性能的净改善很小。即使没有索引的表也要花很多时间才能插入很多行。然后,还原需要运行ALTER TABLE来建立索引。大桌子需要一段时间。当您计算INSERT的时间加上建立索引的额外时间时,它比将传统方法插入具有索引的表中仅快百分之几(低个位数)。
此后处理索引创建的另一个好处是索引存储更加紧凑,因此,如果需要节省磁盘空间,那是使用此技术的更好理由。
我发现通过并行加载多个表对恢复性能更有利。
myloader
的多线程还原工具。 mydumper / myloader的最糟糕的缺点是该文档实际上不存在,因此您必须是一个勇敢的超级用户才能弄清楚如何运行它。另一种策略是使用mysqldump --tab
转储CSV文件而不是SQL脚本。批量加载CSV文件比执行SQL脚本还原数据要快得多。好吧,它转储用于表定义的SQL文件和用于导入数据的CSV文件。它为每个表创建单独的文件。您必须通过加载所有SQL文件来手动重新创建表(这是快速的),然后使用mysqlimport加载CSV数据文件。 mysqlimport工具甚至具有用于并行执行的--use-threads
选项。
使用不同数量的并行线程进行仔细测试。我的经验是4个线程是最好的。随着更大的并行度,InnoDB成为瓶颈。但是您的经验可能会有所不同,具体取决于MySQL的版本和服务器硬件的性能。
最快的还原方法是使用物理备份工具时,最受欢迎的是Percona XtraBackup。这样可以实现快速备份甚至更快的还原。备份文件实际上已经准备好可以复制到位并用作活动表空间文件。缺点是您必须关闭MySQL服务器才能执行还原。