如何在 MySQL innoDB 中重建索引和更新统计信息?
How can I rebuild indexes and update stats in MySQL innoDB?
我有使用 MS SQL 服务器的经验,这对 update statistic and rebuild indexes 可能且有用。我在 MySQL innoDB 中找不到这样的选项,有这样的选项吗?如果没有,MySQL数据库如何创建执行计划? MySQL 是否在每次 UPDATE 和 INSERT 时更新索引和统计信息?
这是用
完成的
ANALYZE TABLE table_name;
了解更多信息 here。
ANALYZE TABLE analyzes and stores the key distribution for a table. During the analysis, the table is locked with a read lock for MyISAM, BDB, and InnoDB. This statement works with MyISAM, BDB, InnoDB, and NDB tables.
为什么?人们几乎从不需要更新统计数据。重建索引的需求就更少了。
OPTIMIZE TABLE tbl;
将重建索引并执行 ANALYZE
;这需要时间。
ANALYZE TABLE tbl;
InnoDB 重建统计数据的速度很快。有了 5.6.6,就更不需要了。
(注意:以上适用于常规 INDEXes
;InnoDB 的 FULLTEXT
确实需要定期重建。)
您还可以使用提供的 CLI 工具 mysqlcheck
来 运行 优化。它有一个 ton of switches,但在最基本的情况下,您只需传入数据库、用户名和密码。
将此添加到 cron 或 Windows 调度程序可以使其成为 automated process。 (MariaDB 但基本相同。)
迄今为止 (mysql 8.0.18) mysql 中没有 suitable 函数来重新创建索引。
由于 mysql 8.0 myisam 正逐渐进入弃用状态,innodb 是当前的主要存储引擎。
在大多数实际情况下,innodb 是最佳选择,它应该使索引保持良好运行。
在大多数实际情况下,innodb 也做得很好,您不需要重新创建索引。几乎总是。
当涉及到具有数百 GB 数据和行的大型 table 并且大量写入情况发生变化时,索引的性能可能会下降。
在我个人的案例中,我看到性能从 ~15 分钟下降到使用二级索引的计数 (*) 到 4300 分钟后写入 table 2 个月,线性时间增加。
重新创建索引后,性能恢复到 15 分钟。
到目前为止,我们有两种选择:
1) 优化 TABLE(或更改 TABLE)
Innodb 不支持优化,所以在这两种情况下,整个 table 将被读取并重新创建。
这意味着您需要临时文件的存储空间,并且取决于 table 很多时间(我遇到过优化需要一周才能完成的情况)。
这将压缩数据并重建所有索引。
尽管没有被官方推荐,但我强烈推荐在大小高达 100GB 的重写 table 上使用 OPTIMIZE 进程。
2) ALTER TABLE DROP KEY -> ALTER TABLE ADD KEY
您按名称手动删除密钥,然后再次手动创建它。在生产环境中,您需要先创建它,然后删除旧版本。
好处:这比优化快得多。缺点:您需要手动创建语法。
"SHOW CREATE TABLE" 可用于快速查看哪些索引可用以及它们是如何被调用的。
附录:
1) 要更新统计数据,您可以使用已经提到的 "ANALYZE TABLE".
2) 如果您在写入繁重的服务器上遇到性能下降,您可能需要重新启动 mysql。当前 mysql (8.0) 中存在一些错误,这些错误可能会导致显着的速度下降而不会出现在错误日志中。最终,这些减速会导致服务器崩溃,但可能需要数周甚至数月的时间才能累积到崩溃,在此过程中,服务器的响应速度会越来越慢。
3) 如果你想重新创建一个大的 table,它需要数周才能完成,或者由于内部数据完整性问题在数小时后失败,你应该执行 CREATE TABLE LIKE, INSERT INTO SELECT *。然后 'atomic RENAME' tables.
4) 如果 INSERT INTO SELECT * 需要数小时到数天才能在巨大的 tables 上完成,您可以使用多线程方法将过程加快约 20-30 倍。您 "partition" 将 table 分成块并并行插入 SELECT *。
对于基本的清理和重新分析,您可以 运行 "OPTIMIZE TABLE ...",它会压缩索引中的开销,并且 运行 ANALYZE TABLE 也是如此,但它是不会重新排序它们并使它们尽可能小和高效。
https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html
但是,如果您希望完全重建索引以获得最佳性能,您可以:
- 删除/重新添加索引(显然)
- 转储/重新加载 table
- ALTER TABLE 和 "change" 使用相同的存储引擎
- REPAIR TABLE(仅适用于 MyISAM、ARCHIVE 和 CSV)
https://dev.mysql.com/doc/refman/8.0/en/rebuilding-tables.html
如果您对字段(索引的一部分)执行 ALTER TABLE 并更改其类型,那么它也会完全重建相关索引。
如MySQL manual所示,有多种重建表的方法。如果你不更改MySQL服务器的版本,并且希望支持各种引擎(MyISAM,InnoDB)的表,那么这样的存储过程可能会派上用场:
CREATE PROCEDURE rebuildTables(in dbName VARCHAR(100))
BEGIN
-- flag marking cursor end
DECLARE done INT DEFAULT FALSE;
DECLARE tableName VARCHAR(255) DEFAULT "";
DECLARE tableEngine VARCHAR(100) DEFAULT "";
-- declare cursor for table names and engine
DEClARE curTables
CURSOR FOR
SELECT TABLE_NAME, ENGINE FROM information_schema.tables where table_schema = dbName and table_type = 'BASE TABLE';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET done = TRUE;
OPEN curTables;
rebuildTables: LOOP
FETCH curTables INTO tableName, tableEngine;
SELECT concat('Processing ', tableName, ' engine ', tableEngine);
IF done THEN
LEAVE rebuildTables;
END IF;
-- rebuild table as adviced in https://dev.mysql.com/doc/refman/5.7/en/rebuilding-tables.html
SET @query = CONCAT('ALTER TABLE ', tableName, ' ENGINE=', tableEngine);
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE curTables;
END;
为了调用它,只需:
CALL rebuildTables('yourDbName');
请注意,此过程可能会花费很多时间,尤其是对于大型表。
使用 CLI,
mysqlcheck -u root -p --auto-repair --optimize --all-databases
我有使用 MS SQL 服务器的经验,这对 update statistic and rebuild indexes 可能且有用。我在 MySQL innoDB 中找不到这样的选项,有这样的选项吗?如果没有,MySQL数据库如何创建执行计划? MySQL 是否在每次 UPDATE 和 INSERT 时更新索引和统计信息?
这是用
完成的ANALYZE TABLE table_name;
了解更多信息 here。
ANALYZE TABLE analyzes and stores the key distribution for a table. During the analysis, the table is locked with a read lock for MyISAM, BDB, and InnoDB. This statement works with MyISAM, BDB, InnoDB, and NDB tables.
为什么?人们几乎从不需要更新统计数据。重建索引的需求就更少了。
OPTIMIZE TABLE tbl;
将重建索引并执行 ANALYZE
;这需要时间。
ANALYZE TABLE tbl;
InnoDB 重建统计数据的速度很快。有了 5.6.6,就更不需要了。
(注意:以上适用于常规 INDEXes
;InnoDB 的 FULLTEXT
确实需要定期重建。)
您还可以使用提供的 CLI 工具 mysqlcheck
来 运行 优化。它有一个 ton of switches,但在最基本的情况下,您只需传入数据库、用户名和密码。
将此添加到 cron 或 Windows 调度程序可以使其成为 automated process。 (MariaDB 但基本相同。)
迄今为止 (mysql 8.0.18) mysql 中没有 suitable 函数来重新创建索引。
由于 mysql 8.0 myisam 正逐渐进入弃用状态,innodb 是当前的主要存储引擎。
在大多数实际情况下,innodb 是最佳选择,它应该使索引保持良好运行。
在大多数实际情况下,innodb 也做得很好,您不需要重新创建索引。几乎总是。
当涉及到具有数百 GB 数据和行的大型 table 并且大量写入情况发生变化时,索引的性能可能会下降。
在我个人的案例中,我看到性能从 ~15 分钟下降到使用二级索引的计数 (*) 到 4300 分钟后写入 table 2 个月,线性时间增加。
重新创建索引后,性能恢复到 15 分钟。
到目前为止,我们有两种选择:
1) 优化 TABLE(或更改 TABLE)
Innodb 不支持优化,所以在这两种情况下,整个 table 将被读取并重新创建。
这意味着您需要临时文件的存储空间,并且取决于 table 很多时间(我遇到过优化需要一周才能完成的情况)。
这将压缩数据并重建所有索引。
尽管没有被官方推荐,但我强烈推荐在大小高达 100GB 的重写 table 上使用 OPTIMIZE 进程。
2) ALTER TABLE DROP KEY -> ALTER TABLE ADD KEY
您按名称手动删除密钥,然后再次手动创建它。在生产环境中,您需要先创建它,然后删除旧版本。
好处:这比优化快得多。缺点:您需要手动创建语法。
"SHOW CREATE TABLE" 可用于快速查看哪些索引可用以及它们是如何被调用的。
附录:
1) 要更新统计数据,您可以使用已经提到的 "ANALYZE TABLE".
2) 如果您在写入繁重的服务器上遇到性能下降,您可能需要重新启动 mysql。当前 mysql (8.0) 中存在一些错误,这些错误可能会导致显着的速度下降而不会出现在错误日志中。最终,这些减速会导致服务器崩溃,但可能需要数周甚至数月的时间才能累积到崩溃,在此过程中,服务器的响应速度会越来越慢。
3) 如果你想重新创建一个大的 table,它需要数周才能完成,或者由于内部数据完整性问题在数小时后失败,你应该执行 CREATE TABLE LIKE, INSERT INTO SELECT *。然后 'atomic RENAME' tables.
4) 如果 INSERT INTO SELECT * 需要数小时到数天才能在巨大的 tables 上完成,您可以使用多线程方法将过程加快约 20-30 倍。您 "partition" 将 table 分成块并并行插入 SELECT *。
对于基本的清理和重新分析,您可以 运行 "OPTIMIZE TABLE ...",它会压缩索引中的开销,并且 运行 ANALYZE TABLE 也是如此,但它是不会重新排序它们并使它们尽可能小和高效。
https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html
但是,如果您希望完全重建索引以获得最佳性能,您可以:
- 删除/重新添加索引(显然)
- 转储/重新加载 table
- ALTER TABLE 和 "change" 使用相同的存储引擎
- REPAIR TABLE(仅适用于 MyISAM、ARCHIVE 和 CSV)
https://dev.mysql.com/doc/refman/8.0/en/rebuilding-tables.html
如果您对字段(索引的一部分)执行 ALTER TABLE 并更改其类型,那么它也会完全重建相关索引。
如MySQL manual所示,有多种重建表的方法。如果你不更改MySQL服务器的版本,并且希望支持各种引擎(MyISAM,InnoDB)的表,那么这样的存储过程可能会派上用场:
CREATE PROCEDURE rebuildTables(in dbName VARCHAR(100))
BEGIN
-- flag marking cursor end
DECLARE done INT DEFAULT FALSE;
DECLARE tableName VARCHAR(255) DEFAULT "";
DECLARE tableEngine VARCHAR(100) DEFAULT "";
-- declare cursor for table names and engine
DEClARE curTables
CURSOR FOR
SELECT TABLE_NAME, ENGINE FROM information_schema.tables where table_schema = dbName and table_type = 'BASE TABLE';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET done = TRUE;
OPEN curTables;
rebuildTables: LOOP
FETCH curTables INTO tableName, tableEngine;
SELECT concat('Processing ', tableName, ' engine ', tableEngine);
IF done THEN
LEAVE rebuildTables;
END IF;
-- rebuild table as adviced in https://dev.mysql.com/doc/refman/5.7/en/rebuilding-tables.html
SET @query = CONCAT('ALTER TABLE ', tableName, ' ENGINE=', tableEngine);
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE curTables;
END;
为了调用它,只需:
CALL rebuildTables('yourDbName');
请注意,此过程可能会花费很多时间,尤其是对于大型表。
使用 CLI,
mysqlcheck -u root -p --auto-repair --optimize --all-databases