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