MySql delete刪除數據後釋放磁盤空間

一、Mysql使用delete刪除數據後,不釋放空間

當你刪除數據 時,mysql並不會回收,被已刪除數據的佔據的存儲空間,以及索引位。而是空在那裏,而是等待新的數據來彌補這個空缺,這樣就有一個缺少,如果一時半 會,沒有數據來填補這個空缺,那這樣就太浪費資源了。所以對於寫比較頻煩的表,要定期進行optimize,一個月一次,看實際情況而定了。

A,原始數據

1,count一下

 
mysql> select count(*) as total from ad_visit_history;  
+---------+  
| total   |  
+---------+  
| 1187096 |                      //總共有118萬多條數據  
+---------+  
1 row in set (0.04 sec)  

 

 2,存放在硬盤中的表文件大小​​​​

[root@BlackGhost test1]# ls |grep visit |xargs -i du {}  
382020    ad_visit_history.MYD                    //數據文件佔了380M  
127116    ad_visit_history.MYI                     //索引文件佔了127M  
12    ad_visit_history.frm                              //結構文件佔了12K  

 

 3,查看一下索引信息

 
mysql> show index from ad_visit_history from test1;     //查看一下該表的索引信息  
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+  
| Table            | Non_unique | Key_name          | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |  
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+  
| ad_visit_history |          0 | PRIMARY           |            1 | id            | A         |     1187096 |     NULL | NULL   |      | BTREE      |         |  
| ad_visit_history |          1 | ad_code           |            1 | ad_code       | A         |          46 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | unique_id         |            1 | unique_id     | A         |     1187096 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | ad_code_ind       |            1 | ad_code       | A         |          46 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | from_page_url_ind |            1 | from_page_url | A         |       30438 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | ip_ind            |            1 | ip            | A         |      593548 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | port_ind          |            1 | port          | A         |       65949 |     NULL | NULL   | YES  | BTREE      |         |  
| ad_visit_history |          1 | session_id_ind    |            1 | session_id    | A         |     1187096 |     NULL | NULL   | YES  | BTREE      |         |  
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+  
8 rows in set (0.28 sec)  

索引信息中的列的信息說明。

Table :表的名稱。 Non_unique :如果索引不能包括重複詞,則爲0。如果可以,則爲1。 Key_name :索引的名稱。 Seq_in_index :索引中的列序列號,從1開始。 Column_name :列名稱。 Collation :列以什麼方式存儲在索引中。在MySQLSHOW INDEX語法中,有值’A’(升序)或NULL(無分類)。 Cardinality :索引中唯一值的數目的估計值。通過運行ANALYZE TABLE或myisamchk -a可以更新。基數根據被存儲爲整數的統計數據來計數,所以即使對於小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL使用該索引的機會就越大。 Sub_part :如果列只是被部分地編入索引,則爲被編入索引的字符的數目。如果整列被編入索引,則爲NULL。 Packed :指示關鍵字如何被壓縮。如果沒有被壓縮,則爲NULL。 Null :如果列含有NULL,則含有YES。如果沒有,則爲空。 Index_type :存儲索引數據結構方法(BTREE, FULLTEXT, HASH, RTREE)

B,刪除一半數據

mysql> delete from ad_visit_history where id>598000;          //刪除一半數據  
Query OK, 589096 rows affected (4 min 28.06 sec)  
  
[root@BlackGhost test1]# ls |grep visit |xargs -i du {}              //相對應的MYD,MYI文件大小沒有變化  
382020    ad_visit_history.MYD   
127116    ad_visit_history.MYI  
12    ad_visit_history.frm  

按常規思想來說,如果在數據庫中刪除了一半數據後,相對應的.MYD,.MYI文件也應當變爲之前的一半。但是刪除一半數據後,.MYD.MYI盡然連1KB都沒有減少 ,這是多麼的可怕啊。

我們在來看一看,索引信息

Mysql> show index from ad_visit_history;    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
| Table            | Non_unique | Key_name          | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
| ad_visit_history |          0 | PRIMARY           |            1 | id            | A         |      598000 |     NULL | NULL   |      | BTREE      |         |    
| ad_visit_history |          1 | ad_code           |            1 | ad_code       | A         |          23 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | unique_id         |            1 | unique_id     | A         |      598000 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | ad_code_ind       |            1 | ad_code       | A         |          23 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | from_page_url_ind |            1 | from_page_url | A         |       15333 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | ip_ind            |            1 | ip            | A         |      299000 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | port_ind          |            1 | port          | A         |       33222 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | session_id_ind    |            1 | session_id    | A         |      598000 |     NULL | NULL   | YES  | BTREE      |         |    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
8 rows in set (0.00 sec)    

對比一下,這次索引查詢和上次索引查詢,裏面的數據信息基本上是上次一次的一本,這點還是合乎常理。

C,用optimize table來優化一下

注意:使用optimize命令會鎖表,慎用

mysql> optimize table ad_visit_history;                                             //刪除數據後的優化  
+------------------------+----------+----------+----------+  
| Table                  | Op       | Msg_type | Msg_text |  
+------------------------+----------+----------+----------+  
| test1.ad_visit_history | optimize | status   | OK       |  
+------------------------+----------+----------+----------+  
1 row in set (1 min 21.05 sec)  

 

 1,查看一下.MYD,.MYI文件的大小

[root@BlackGhost test1]# ls |grep visit |xargs -i du {}  
182080    ad_visit_history.MYD                                          //數據文件差不多爲優化前的一半  
66024    ad_visit_history.MYI                                             //索引文件也一樣,差不多是優化前的一半  
12    ad_visit_history.frm  

 

 2,查看一下索引信息

mysql> show index from ad_visit_history;    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
| Table            | Non_unique | Key_name          | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
| ad_visit_history |          0 | PRIMARY           |            1 | id            | A         |      598000 |     NULL | NULL   |      | BTREE      |         |    
| ad_visit_history |          1 | ad_code           |            1 | ad_code       | A         |          42 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | unique_id         |            1 | unique_id     | A         |      598000 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | ad_code_ind       |            1 | ad_code       | A         |          42 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | from_page_url_ind |            1 | from_page_url | A         |       24916 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | ip_ind            |            1 | ip            | A         |      598000 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | port_ind          |            1 | port          | A         |       59800 |     NULL | NULL   | YES  | BTREE      |         |    
| ad_visit_history |          1 | session_id_ind    |            1 | session_id    | A         |      598000 |     NULL | NULL   | YES  | BTREE      |         |    
+------------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+    
8 rows in set (0.00 sec)    

 

從以上數據我們可以得出,ad_code,ad_code_ind,from_page_url_ind等索引機會差不多都提高了85%,這樣效率提高了好多。

 

二、Mysql相關命令(是否釋放磁盤空間)

drop table table_name 立刻釋放磁盤空間 ,不管是 Innodb和MyISAM ;

truncate table table_name立刻釋放磁盤空間 ,不管是 Innodb和MyISAM;

delete from table_name 刪除表的全部數據,對於MyISAM 會立刻釋放磁盤空間 ,而InnoDB 不會釋放磁盤空間;

delete from table_name where xx 帶條件的刪除, 不管是innodb還是MyISAM都不會釋放磁盤空間;

delete操作後使用optimize table table_name 釋放磁盤空間,優化表期間會鎖定表,所以要在空閒時段執行optimize table ,測試十幾個G數據的表執行optimize table 大概20多分鐘。

注:delete刪除數據的時候,mysql並沒有把數據文件刪除,而是將數據文件的標識位刪除,沒有整理文件,因此不會徹底釋放空間。被刪除的數據將會被保存在一個鏈接清單中,當有新數據寫入的時候,mysql會利用這些已刪除的空間再寫入。即,刪除操作會帶來一些數據碎片,正是這些碎片在佔用硬盤空間。
OPTIMIZE TABLE命令優化表,該命令會重新利用未使用的空間,並整理數據文件的碎片;該命令將會整理表數據和相關的索引數據的物理存儲空間,用來減少佔用的磁盤空間,並提高訪問表時候的IO性能;但是具體對錶產生的影響是依賴於表使用的存儲引擎的。該命令對視圖無效。

使用optimize table table_name出現Table does not support optimize, doing recreate + analyze instead 的解決辦法:

innodb的數據庫不支持optimize,可以用 ALTER TABLE table.name ENGINE='InnoDB';對舊錶以複製的方式新建一個新表,然後刪除舊錶。操作前最好備份表。
重新啓動mysql ,在啓動的時候指定–skip-new或者–safe-mode選項來支持optimize功能 再執行optimize table table_name

>/usr/local/mysql/bin/mysqladmin -uroot -p shutdown  --停止mysql
>/usr/local/mysql/bin/mysqld --skip-new &  --啓動mysql
>mysql -uroot -p   --在服務器上連接mysql
mysql>use db_name;

刪除數據並執行了optimize table釋放了磁盤空間;optimize命令優化表 不要頻繁操作,另外還發現執行optimize命令 Innodb 引擎的數據庫下ibtmp1 文件由原來的幾個G優化成12M了。
但如果數據每天都大量插入,刪除數據後不執行optimize table insert 數據的時候會佔用已經刪除那部分數據的空間,數據文件所佔用的磁盤空間短時間並不會增長,所以要減少數據文件佔用磁盤空間,可以對錶進行壓縮。
 

三、是否對InnoDB數據表進行壓縮

適用於I/O爲系統主要瓶頸的應用系統,表壓縮可以增加I/O吞吐,但是同時解壓縮會耗費cpu資源。所以本質上是以cpu換I/O。

 

優點:

1、文件大小減小(可達50%以上)

壓縮後

2、 查詢速度變快(count * 約減少20%以上時間)

如何設置mysql innodb 表的壓縮:

第一,mysql的版本需要大於5.5
第二,設置innodb_file_format=barracuda
第三,create table或者alter talble 增加 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;(默認的key_block_size=16)
根據經驗,一般壓縮比例可以達到30%-40%

順序不能改變, 先設置字符集給事爲 innodb_file_format=barracuda,然後再建表或者修改表的compaesed 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章