15.7.3.4 优化表语句
OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL]
TABLE tbl_name [, tbl_name] ...
OPTIMIZE TABLE
语句重组了表数据的物理存储以及相关索引数据,以减少存储空间并提高当访问表时的I/O效率。对每个表执行的确切更改取决于该表所使用的存储引擎。
在以下情况下使用 OPTIMIZE TABLE
,取决于表的类型:
-
在对一个具有自己的.ibd文件的
innodb_file_per_table
选项启用的InnoDB
表执行了大量插入、更新或删除操作。表和索引被重组,磁盘空间可以回收给操作系统使用。 -
在对
innodb_optimize_fulltext_only=1
配置选项设置后,对一个包含在FULLTEXT
索引中的innodb_ft_num_word_optimize
选项指定的单词数量进行了大量插入、更新或删除操作的InnoDB
表。为了保持索引维护期间的时间合理,运行一系列OPTIMIZE TABLE
语句直到搜索索引完全更新。 -
在删除大量
MyISAM
或ARCHIVE
表的记录,或者对具有变长行(包含VARCHAR
、VARBINARY
、BLOB
或TEXT
列的)的MyISAM
或ARCHIVE
表执行了大量插入、更新或删除操作。删除的记录被保持在一个链表中,随后的INSERT
操作重用旧的行位置。可以使用OPTIMIZE TABLE
语句回收未使用的空间并对数据文件进行碎片整理。在对表执行了大量更改后,这个语句可能会显著提高访问该表的性能。
OPTIMIZE TABLE
语句支持InnoDB
、MyISAM
和 ARCHIVE
表。OPTIMIZE TABLE
语句也支持NDB
表的动态列。它不适用于固定宽度列的内存表,也不适用于磁盘数据表。对OPTIMIZE
语句在 NDB 集群表上的性能可以通过 --ndb-optimization-delay
控制,控制OPTIMIZE TABLE
之间的等待时间。更多信息,请参阅 Section 25.2.7.11, “Previous NDB Cluster Issues Resolved in NDB Cluster 8.4”。
对于 NDB 集群表,OPTIMIZE TABLE
可以在执行 OPTIMIZE
操作的 SQL 线程被中断(例如,通过杀死执行 OPTIMIZE
操作的 SQL 线程)。
默认情况下,OPTIMIZE TABLE
不支持使用其他存储引擎创建的表格,并返回一个结果指示这一缺乏支持。您可以通过在启动mysqld时使用--skip-new
选项,使OPTIMIZE TABLE
支持其他存储引擎。在这种情况下,OPTIMIZE TABLE
将被映射到ALTER TABLE
。
这个语句不支持视图。
OPTIMIZE TABLE
支持分区表。有关使用该语句与分区表和表格分区的信息,请参阅第26.3.4节,“分区维护”。
默认情况下,服务器将OPTIMIZE TABLE
语句写入二进制日志,以便复制到副本。要抑制日志记录,请指定可选的NO_WRITE_TO_BINLOG
关键字或其别名LOCAL
。您必须拥有OPTIMIZE_LOCAL_TABLE
权限才能使用此选项。
OPTIMIZE TABLE
返回一个结果集,其列显示在以下表格中。
Column | Value |
---|---|
Table |
表名 |
Op |
始终为 optimize |
Msg_type |
状态、错误、信息、注意或警告 |
Msg_text |
信息性消息 |
OPTIMIZE TABLE
表格捕获并抛出在从旧文件复制表格统计信息到新创建的文件期间发生的任何错误。例如,如果用户 ID 与mysqld 进程的用户 ID 不同,OPTIMIZE TABLE
生成一个“无法更改文件所有权”的错误,除非mysqld 由 root
用户启动。
对于InnoDB
表格,OPTIMIZE TABLE
被映射到ALTER TABLE ... FORCE
,该语句重建表格以更新索引统计信息并释放未使用的空间。这个过程在OPTIMIZE TABLE
的输出中显示,当您对一个InnoDB
表格运行该语句时,如下所示:
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
使用在线DML对普通和分区的InnoDB
表进行优化,减少了并发DML操作的停机时间。表重建由OPTIMIZE TABLE
触发,在执行过程中只会短暂地获取一个排他性表锁。在准备阶段,元数据被更新,并创建一个临时表。在提交阶段,表的元数据更改被提交。
OPTIMIZE TABLE
使用在线DML在以下条件下重建表:
-
当
old_alter_table
系统变量启用时。 -
服务器启动时使用
--skip-new
选项。
OPTIMIZE TABLE
使用在线DML不支持包含FULLTEXT
索引的InnoDB
表。相反,使用了表复制方法。
InnoDB
使用页面分配方式存储数据,不像遗留存储引擎(如MyISAM
)那样会出现碎片。当考虑是否运行优化时,考虑服务器预期处理的交易工作负载:
-
某种程度的碎片是可接受的。
InnoDB
只填充页面到93%满,以留出空间更新数据而不需要分割页面。 -
删除操作可能会留下空洞,使得页面比理想状态更为空,这可能值得优化表格。
-
更新行通常在同一页面内重写数据,除非有足够的空间可用,否则依赖于数据类型和行格式。请参阅第17.9.1.5节,“InnoDB表的压缩工作原理”和第17.10节,“InnoDB行格式”。
-
高并发工作负载可能会随着时间的推移在索引中留下空洞,因为
InnoDB
通过其MVCC机制保留多个版本相同数据的不同版本。请参阅第17.3节,“InnoDB多版本控制”。
OPTIMIZE TABLE
对于普通和分区的InnoDB
表进行在线优化。否则,MySQL在运行OPTIMIZE TABLE
时锁定表。
OPTIMIZE TABLE
不会对R-树索引进行排序,如POINT
列上的空间索引。(问题#23578)