mysql optimize table

语法结构:mysql

OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name [, tbl_name] ...

optimize table 会重组表数据和索引的物理存储,减小对存储空间使用和提高访问表时io效率。optimize table后,表的变化和存储引擎也有关。sql

如下场景使用 optimize table,和表的类型有关:
1.innodb存储引擎+独立表空间,optimize table会重组表和索引数据,磁盘空间被回收。
2.插入、更新、删除的列是innodb表中fulltext索引的列,要先设置innodb_optimize_fulltext_only=1。
为了将对索引的维护设置在一个合理的时间内,能够设置innodb_ft_num_word_optimize指定一次处理多少个words,执行屡次optimize table操做直到索引更新结束。
3.删除myisam、archive存储引擎表中大量数据,或者对myisam、archive表变长的行作了大量修改。删除的行被为维护在一个链表中,以后的insert能够重用这些位置。
可使用optimize TABLE来回收未使用的空间并整理数据文件。在对表进行了大量更改以后,该语句还能够提升使用该表的语句的性能,有时效果显著。数据库

optimize table须要对表具备select、insert权限。并发


optimize table支持innodb、myisam、archive存储引擎的表。mvc


默认是不支持其余存储引擎的表,会返回不支持的提示信息。要想支持其余存储引擎,可使用mysqld --skip-new选项开启对其余存储引擎的支持。使用--skip-new选项后,optimize table仅仅被映射成alter table操做。高并发


不支持对view进行optimize。sqlserver


optimize table支持分区表。性能

缺省,optimize table被记入二进制日志,并复制到slave节点。可使用no_write_binlog或local取消对二进制日志的写入。测试

 

对innodb表执行optimize tablespa

对于innodb表,optimize table被映射成alter table ... force,重建表和更新索引统计信息并释放空间。
对innodb执行optimize table操做,输出相似下面的结果:

> 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 触发表重建,内部执行alter table ... force操做。
在prepare阶段和commit阶段会对表加上排他锁。在prepare阶段会更新元数据并建立一个内部中间表,在commit阶段提交对元数据的修改。

 

optimize table在如下场景使用数据拷贝的方式进行重建表:
1.开启了old_alter_table系统变量
2.使用了mysqld --skip-new选项启动数据库

若是innodb表包含fulltext索引,是不支持optimize table使用在线ddl的。只能使用数据拷贝的方式。 

InnoDB使用页面分配方法存储数据,不像传统存储引擎(好比MyISAM)那样存在碎片问题。执行optimize table以前要考虑事务的负载大小:
·有些级别的碎片是系统预期的。innodb只会插入数据到页面的93%,剩下的空间是给update预留的,以避免出现页的分裂
·删除操做可能会留下不少空隙,执行optimize table是有意义的
·更新一般是在相同的页中重写数据,空间是否充足取决于行格式和列的数据类型
·因为innodb的mvcc机制,高并发环境可能会致使索引产生空隙

 

对myisam表执行optimize table
对于myisam表,optimize table操做执行如下工做:
1.若是表含有删除的列、分列的列,optimize table会修复表
2.若是索引页没有排序,optimize table会将索引页进行排序
3.若是表的统计信息不是最新的,optimize table会更新索引信息

 

补充:

对innodb表执行optimize table操做的时候,会报"Table does not support optimize, doing recreate + analyze instead"提示。有人直接说optimize table不支持innodb表。其实并不能这么理解。

下面是测试结果:

Server version: 5.7.19 MySQL Community Server (GPL)

CREATE TABLE m_test(id int unsigned, body text) engine=myisam charset=utf8;
CREATE TABLE i_test(id int unsigned, body text) engine=innodb charset=utf8;

INSERT INTO m_test VALUES(1, 'AAAAA');
INSERT INTO m_test VALUES(2, 'BBBBB');
INSERT INTO m_test VALUES(3, 'CCCCC');
INSERT INTO m_test VALUES(4, 'DDDDD');
INSERT INTO m_test VALUES(5, 'EEEEE');
INSERT INTO i_test VALUES(1, 'AAAAA');
INSERT INTO i_test VALUES(2, 'BBBBB');
INSERT INTO i_test VALUES(3, 'CCCCC');
INSERT INTO i_test VALUES(4, 'DDDDD');
INSERT INTO i_test VALUES(5, 'EEEEE');

#屡次插入相同的数据:
INSERT INTO m_test SELECT id, body FROM m_test;
INSERT INTO i_test SELECT id, body FROM i_test;
...

查看表和文件的大小:

ysql> select count(*) from m_test;
+----------+
| count(*) |
+----------+
| 83886080 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from i_test;
+----------+
| count(*) |
+----------+
| 83886080 |
+----------+
1 row in set (36.04 sec) #明显慢不少
mysql> 
# ll |grep test
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 i_test.frm
-rw-r----- 1 mysql mysql 3267362816 Sep  2 10:30 i_test.ibd
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 m_test.frm
-rw-r----- 1 mysql mysql 1677721600 Sep  2 10:26 m_test.MYD
-rw-r----- 1 mysql mysql       1024 Sep  2 10:26 m_test.MYI

删除必定数据后查看表和文件的大小:

mysql> DELETE FROM i_test WHERE id < 3;
mysql> DELETE FROM m_test WHERE id < 3;
# ll |grep test
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 i_test.frm
-rw-r----- 1 mysql mysql 3267362816 Sep  2 10:39 i_test.ibd
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 m_test.frm
-rw-r----- 1 mysql mysql 1677721600 Sep  2 10:37 m_test.MYD
-rw-r----- 1 mysql mysql       1024 Sep  2 10:37 m_test.MYI
mysql> select count(*) from m_test;
+----------+
| count(*) |
+----------+
| 50331648 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from i_test;
+----------+
| count(*) |
+----------+
| 50331648 |
+----------+
1 row in set (52.91 sec)

分别执行optimize table操做:

mysql> optimize table m_test;
+-------------+----------+----------+----------+
| Table       | Op       | Msg_type | Msg_text |
+-------------+----------+----------+----------+
| test.m_test | optimize | status   | OK       |
+-------------+----------+----------+----------+
1 row in set (8.49 sec)

mysql> optimize table i_test;
+-------------+----------+----------+-------------------------------------------------------------------+
| Table       | Op       | Msg_type | Msg_text                                                          |
+-------------+----------+----------+-------------------------------------------------------------------+
| test.i_test | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| test.i_test | optimize | status   | OK                                                                |
+-------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (47.73 sec)

mysql> 
# ll |grep test
-rw-r----- 1 mysql mysql       8586 Sep  2 10:42 i_test.frm
-rw-r----- 1 mysql mysql 2243952640 Sep  2 10:43 i_test.ibd
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 m_test.frm
-rw-r----- 1 mysql mysql 1006632960 Sep  2 10:41 m_test.MYD
-rw-r----- 1 mysql mysql       1024 Sep  2 10:41 m_test.MYI

从上面的结果能够看到,不管是innodb、仍是myisam表都被收缩了。

 

使用mysqld --skip-new重启mysqlserver后,再次对innodb表执行optimize table操做:

mysql> optimize table i_test;
Query OK, 50331648 rows affected (3 min 10.82 sec)
Records: 50331648  Duplicates: 0  Warnings: 0

mysql> 
# ll |grep test
-rw-r----- 1 mysql mysql       8586 Sep  2 10:47 i_test.frm
-rw-r----- 1 mysql mysql 1962934272 Sep  2 10:50 i_test.ibd
-rw-r----- 1 mysql mysql       8586 Sep  2 10:03 m_test.frm
-rw-r----- 1 mysql mysql 1006632960 Sep  2 10:41 m_test.MYD
-rw-r----- 1 mysql mysql       1024 Sep  2 10:41 m_test.MYI

能够看到,innodb表再次发生了收缩。

 

结论:
"Table does not support optimize, doing recreate + analyze instead"并非说innodb不支持optimize table。
由于对于innodb表,optimize table被映射成alter table ... force,重建表和更新索引统计信息并释放空间。

相关文章
相关标签/搜索