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

相關文章
相關標籤/搜索