語法結構: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,重建表和更新索引統計信息並釋放空間。