OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL]
TABLE tbl_name [, tbl_name] ...
OPTIMIZE TABLE
重新组织表数据和相关索引数据的物理存储,以减少存储空间并提高访问表时的 I/O 效率。每个表的确切变化取决于该表使用的 存储引擎。
在以下情况下使用 OPTIMIZE TABLE
,具体取决于表的类型:
-
在对
InnoDB
表进行大量插入、更新或删除操作后,因为它使用了 .ibd 文件,并且启用了innodb_file_per_table
选项。表和索引将被重新组织,磁盘空间可以被操作系统回收。 -
在对
InnoDB
表的FULLTEXT
索引进行大量插入、更新或删除操作后。首先设置配置选项innodb_optimize_fulltext_only=1
。为了保持索引维护期限在合理的时间内,设置innodb_ft_num_word_optimize
选项以指定要更新的单词数量,然后运行一系列OPTIMIZE TABLE
语句,直到搜索索引被完全更新。 -
在删除
MyISAM
或ARCHIVE
表的大部分数据,或者对MyISAM
或ARCHIVE
表进行了大量更改(具有VARCHAR
、VARBINARY
、BLOB
或TEXT
列)。删除的行将被维护在链表中,后续的INSERT
操作将重用旧的行位置。可以使用OPTIMIZE TABLE
回收未使用的空间并碎片数据文件。在对表进行了大量更改后,这个语句也可以提高使用该表的语句的性能,有时性能提高非常明显。
该语句需要 SELECT
和 INSERT
权限来访问该表。
OPTIMIZE TABLE
适用于 InnoDB
、MyISAM
和 ARCHIVE
表。OPTIMIZE TABLE
也支持内存中的 NDB
表的动态列。它不适用于固定宽度列的内存表,也不适用于磁盘数据表。可以使用 --ndb-optimization-delay
选项来调整 NDB Cluster 表上的 OPTIMIZE
性能。有关更多信息,请参阅 第 25.2.7.11 节,“NDB Cluster 8.0 中解决的以前的问题”。
对于 NDB Cluster 表,OPTIMIZE TABLE
可以被(例如)杀死执行 OPTIMIZE
操作的 SQL 线程所中断。
默认情况下,OPTIMIZE TABLE
不适用于使用其他存储引擎创建的表,并返回一个结果,表明缺乏支持。你可以通过启动 mysqld with the --skip-new
选项,使 OPTIMIZE TABLE
适用于其他存储引擎。在这种情况下,OPTIMIZE TABLE
只是映射到 ALTER TABLE
。
该语句不适用于视图。
OPTIMIZE TABLE
支持分区表。有关使用该语句与分区表和表分区的信息,请参阅 第 26.3.4 节,“分区维护”。
默认情况下,服务器将 OPTIMIZE TABLE
语句写入二进制日志,以便复制到副本。要抑制日志记录,请指定可选的 NO_WRITE_TO_BINLOG
关键字或其别名 LOCAL
。
OPTIMIZE TABLE
返回一个结果集,具有以下表中的列。
Column | Value |
---|---|
表 |
表名 |
Op |
始终 optimize |
Msg_type |
状态 、错误 、信息 、注意 或 警告 |
Msg_text |
信息性消息 |
OPTIMIZE TABLE
捕获并抛出在从旧文件复制表统计信息到新创建的文件时发生的任何错误。例如,如果 .MYD
或 .MYI
文件的所有者用户 ID 与 mysqld 进程的用户 ID 不同,OPTIMIZE TABLE
生成“无法更改文件所有权”错误,除非 mysqld 由根用户启动。
对于 InnoDB
表,OPTIMIZE TABLE
映射到 ALTER TABLE ... FORCE
,该语句重建表以更新索引统计信息和释放聚簇索引中的未使用空间。这将在 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
使用 在线 DDL 对常规和分区的 InnoDB
表,减少了并发 DML 操作的停机时间。由 OPTIMIZE TABLE
触发的表重建是在原地完成的。在准备阶段和提交阶段,仅briefly 获取独占表锁。在准备阶段,元数据被更新,并创建了中间表。在提交阶段,表元数据更改被提交。
OPTIMIZE TABLE
在以下情况下使用表副本方法重建表:
-
当
old_alter_table
系统变量启用时。 -
当服务器使用
--skip-new
选项启动时。
OPTIMIZE TABLE
使用 在线 DDL 不支持包含 FULLTEXT
索引的 InnoDB
表。相反,使用表副本方法。
InnoDB
使用页分配方法存储数据,不像遗留存储引擎(如 MyISAM
)那样遭受碎片化。当考虑是否运行 optimize 时,考虑服务器预期处理的事务工作负载:
-
一些碎片化是预期的。
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-tree 索引(如 POINT
列上的空间索引)进行排序。(Bug #23578)