OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL]
TABLE tbl_name [, tbl_name] ...
OPTIMIZE TABLE 重新组织表数据和相关索引数据的物理存储,以减少存储空间并提高访问表的 I/O 效率。对每个表进行的具体更改取决于该表使用的 存储引擎。
根据表的类型,在以下情况下使用 OPTIMIZE TABLE
在对具有自己 .ibd 文件 的
InnoDB表进行大量插入、更新或删除操作后,因为它是使用启用了innodb_file_per_table选项创建的。表和索引将被重新组织,并且磁盘空间可以被回收供操作系统使用。在对包含
FULLTEXT索引的InnoDB表执行大量的插入、更新或删除操作后,首先设置配置选项innodb_optimize_fulltext_only=1。为了将索引维护时间控制在合理范围内,请设置innodb_ft_num_word_optimize选项以指定要更新的搜索索引中的单词数量,并运行一系列OPTIMIZE TABLE语句,直到搜索索引完全更新。在删除
MyISAM或ARCHIVE表的大部分数据,或对具有可变长度行的MyISAM或ARCHIVE表(包含VARCHAR、VARBINARY、BLOB或TEXT列的表)进行大量更改后。已删除的行将保存在一个链接列表中,后续的INSERT操作会重用旧的行位置。您可以使用OPTIMIZE TABLE来回收未使用的空间并对数据文件进行碎片整理。在对表进行大量更改后,此语句还可以提高使用该表的语句的性能,有时甚至可以显著提高性能。
OPTIMIZE TABLE适用于InnoDB、MyISAM和ARCHIVE表。还支持OPTIMIZE TABLE用于内存中NDB表的动态列。它不适用于内存中表的固定宽度列,也不适用于磁盘数据表。可以使用--ndb-optimization-delay调整OPTIMIZE在 NDB Cluster 表上的性能,该选项控制OPTIMIZE TABLE处理一批行之间等待的时间长度。有关更多信息,请参见第 25.2.7.11 节,“在 NDB Cluster 9.0 中解决的先前 NDB Cluster 问题”。
对于 NDB Cluster 表,可以通过(例如)终止执行OPTIMIZE操作的 SQL 线程来中断OPTIMIZE TABLE。
默认情况下,OPTIMIZE TABLE不适用于使用任何其他存储引擎创建的表,并返回一个结果,指示此不支持情况。您可以通过以下方式使OPTIMIZE TABLE适用于其他存储引擎:使用--skip-new选项启动mysqld。在这种情况下,OPTIMIZE TABLE将映射到ALTER TABLE。
此语句不适用于视图。
OPTIMIZE TABLE支持分区表。有关在分区表和表分区中使用此语句的信息,请参见第 26.3.4 节,“分区维护”。
默认情况下,服务器将OPTIMIZE TABLE语句写入二进制日志,以便它们复制到副本。要抑制日志记录,请指定可选的NO_WRITE_TO_BINLOG关键字或其别名LOCAL。您必须具有OPTIMIZE_LOCAL_TABLE权限才能使用此选项。
OPTIMIZE TABLE返回一个结果集,其中包含下表中显示的列。
| 列 | 值 |
|---|---|
表 |
表名 |
操作 |
始终为optimize |
消息类型 |
status、error、info、note或warning |
消息文本 |
一条信息性消息 |
OPTIMIZE TABLE表会捕获并抛出从旧文件复制表统计信息到新创建文件的过程中出现的任何错误。例如,如果.MYD或.MYI文件的拥有者的用户 ID 与mysqld进程的用户 ID 不同,则OPTIMIZE TABLE会生成“无法更改文件的拥有权”错误,除非mysqld是由root用户启动的。
对于InnoDB表,OPTIMIZE TABLE映射到ALTER TABLE ... FORCE,它会重建表以更新索引统计信息并释放聚簇索引中未使用的空间。当您在InnoDB表上运行它时,这将在OPTIMIZE TABLE的输出中显示,如下所示
mysql> OPTIMIZE TABLE foo;
+----------+----------+----------+-------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+----------+----------+----------+-------------------------------------------------------------------+
| test.foo | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| test.foo | optimize | status | OK |
+----------+----------+----------+-------------------------------------------------------------------+
OPTIMIZE TABLE对常规和分区InnoDB表使用在线 DDL,这减少了并发 DML 操作的停机时间。由OPTIMIZE TABLE触发的表重建是在原地完成的。在操作的准备阶段和提交阶段,只会在短暂时间内获取排它表锁。在准备阶段,将更新元数据并创建中间表。在提交阶段,将提交表元数据更改。
OPTIMIZE TABLE在以下情况下使用表复制方法重建表
当
old_alter_table系统变量启用时。当服务器使用
--skip-new选项启动时。
使用在线 DDL的OPTIMIZE TABLE不支持包含FULLTEXT索引的InnoDB表。相反,将使用表复制方法。
InnoDB使用页面分配方法存储数据,不会像传统存储引擎(如MyISAM)那样遭受碎片化。在考虑是否运行优化时,请考虑服务器预期处理的交易工作负载
预期会存在一定程度的碎片化。
InnoDB仅将页面填充到 93% 满,以留出空间用于更新,而无需拆分页面。删除操作可能会留下间隙,使页面填充率低于预期,这可能使优化表变得有意义。
对行的更新通常会在同一页面内重写数据,具体取决于数据类型和行格式,前提是有足够的空间可用。请参见第 17.9.1.5 节,“InnoDB 表的压缩工作原理”和第 17.10 节,“InnoDB 行格式”。
高并发工作负载可能会随着时间的推移在索引中留下间隙,因为
InnoDB通过其MVCC机制保留同一数据的多个版本。请参见第 17.3 节,“InnoDB 多版本控制”。
对于MyISAM表,OPTIMIZE TABLE的工作方式如下
如果表包含已删除或拆分的行,则修复该表。
如果索引页面未排序,则对其进行排序。
如果表的统计信息未更新(并且修复无法通过排序索引来完成),则更新这些统计信息。
OPTIMIZE TABLE对常规和分区InnoDB表在线执行。否则,MySQL 在OPTIMIZE TABLE运行期间会锁定该表。
OPTIMIZE TABLE不会对 R 树索引进行排序,例如对POINT列的空间索引。(错误号 23578)