在MySQL中,我們經常會使用VARCHAR
、TEXT
、BLOB
等可變長度的文本數據類型。不過,當我們使用這些數據類型之后,我們就不得不做一些額外的工作——MySQL數據表碎片整理。
那么,為什么在使用這些數據類型之后,我們就要對MySQL定期進行碎片整理呢?
現在,我們先來看一個具體的例子。在這里,我們使用如下SQL語句在MySQL自帶的TEST
數據庫中創建名為DEMO
的數據表並插入5條測試數據。
- --創建DEMO表
- CREATE TABLE DEMO(
- id int unsigned,
- body text
- ) engine=myisam charset=utf8;
- --插入5條測試數據
- INSERT INTO DEMO VALUES(1, 'AAAAA');
- INSERT INTO DEMO VALUES(2, 'BBBBB');
- INSERT INTO DEMO VALUES(3, 'CCCCC');
- INSERT INTO DEMO VALUES(4, 'DDDDD');
- INSERT INTO DEMO VALUES(5, 'EEEEE');
然后我們以這5條測試數據為基礎,使用如下INSERT INTO
語句重復執行多次進行復制性插入。
INSERT INTO DEMO SELECT id, body FROM DEMO;
使用INSERT INTO語句多次插入產生總共約262萬條數據
眾所周知,MySQL中MyISAM表的數據是以文件形式存儲的,我們可以在MySQL存儲數據的文件夾中找到數據庫test目錄下的demo.MYD
文件。此時,我們可以看到demo.MYD
文件的大小約為50MB。
此時,假如我們需要刪除DEMO
表中所有ID
列小於3的數據(即1和2),於是我們執行如下SQL語句:
DELETE FROM DEMO WHERE id < 3
此時,我們可以看到DEMO
表中的數據量只有原來的3/5:
DEMO
表中的現有數據量只有原來的3/5,按理說,這個時候demo.MYD
文件的大小也應該只有原來的3/5左右。不過,我們再次查看demo.MYD
文件時,卻驚奇地發現該文件的大小一點都沒有變!
那么就究竟是怎么一回事呢?原來,在MySQL中,如果我們刪除了表中的大量數據,或者我們對含有可變長度文本數據類型(VARCHAR
,TEXT
或BLOB
)的表進行了很多更改,不過被刪除的數據記錄仍然被保持在MySQL的鏈接清單中,因此數據存儲文件的大小並不會隨着數據的刪除而減小。
當我們確定數據需要被清除掉時,那么這些數據就已經成了無用的數據,但是按照MySQL的處理方式,這些數據仍然會占用我們的磁盤空間,從而造成了極大的資源浪費。不僅如此,過大的數據文件還會導致MySQL執行相關數據操作時需要耗費更多的性能和時間。因此,對MySQL的某些數據表進行碎片整理是非常有必要的。
對MySQL進行碎片整理的方法非常簡單,因為MySQL已經給我們提供了對應的SQL指令,這個SQL指令就是OPTIMIZE TABLE
,其完整語法如下:
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE table_name1 [, table_name2] ...
從上面的語法描述中,我們可以得知,OPTIMIZE TABLE
可以一次性對多個表進行碎片整理,只需要在OPTIMIZE TABLE
后面接多個表名,並以英文逗號隔開即可。
此外,OPTIMIZE TABLE
語句有兩個可選的關鍵字:LOCAL
和NO_WRITE_TO_BINLOG
。在默認情況下,OPTIMIZE TABLE
語句將會被記錄到二進制日志中,如果我們指定了LOCAL
或NO_WRITE_TO_BINLOG
關鍵字,則不會記錄。當然,一般情況下,我們也無需關注這兩個關鍵字。
現在,我們就使用OPTIMIZE TABLE
語句對剛才的DEMO
表進行碎片整理。
然后,我們再來查看demo.MYD
文件,此時我們就會發現demo.MYD
文件的大小已經減小到約為原來的3/5了。
備注:
1.MySQL官方建議不要經常(每小時或每天)進行碎片整理,一般根據實際情況,只需要每周或者每月整理一次即可。
2.OPTIMIZE TABLE
只對MyISAM,BDB和InnoDB表起作用,尤其是MyISAM表的作用最為明顯。此外,並不是所有表都需要進行碎片整理,一般只需要對包含上述可變長度的文本數據類型的表進行整理即可。
3.在OPTIMIZE TABLE
運行過程中,MySQL會鎖定表。
4.默認情況下,直接對InnoDB引擎的數據表使用OPTIMIZE TABLE
,可能會顯示「 Table does not support optimize, doing recreate + analyze instead」的提示信息。這個時候,我們可以用mysqld --skip-new
或者mysqld --safe-mode
命令來重啟MySQL,以便於讓其他引擎支持OPTIMIZE TABLE
。