mysql optimize table
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql optimize table相关的知识,希望对你有一定的参考价值。
语法结构:
OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [, tbl_name] ...
optimize table 会重组表数据和索引的物理存储,减少对存储空间使用和提升访问表时io效率。optimize table后,表的变化和存储引擎也有关。
以下场景使用 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存储引擎的表。
默认是不支持其他存储引擎的表,会返回不支持的提示信息。要想支持其他存储引擎,可以使用mysqld --skip-new选项开启对其他存储引擎的支持。使用--skip-new选项后,optimize table仅仅被映射成alter table操作。
不支持对view进行optimize。
optimize table支持分区表。
缺省,optimize table被记入二进制日志,并复制到slave节点。可以使用no_write_binlog或local取消对二进制日志的写入。
对innodb表执行optimize table
对于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选项启动数据库
不是所有的场景都可以使用在线ddl。如果innodb表包含fulltext索引,是不支持optimize table的在线ddl的。只能使用数据拷贝的方式。
alter table使用的是数据copy;alter table ... force使用的是在线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,重建表和更新索引统计信息并释放空间。
以上是关于mysql optimize table的主要内容,如果未能解决你的问题,请参考以下文章
小白学习MySQL - InnoDB支持optimize table?