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選項啟動數據庫

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM