1. 程式人生 > >mysql innodb引擎 長時間使用後,資料檔案遠大於實際資料量,導致空間不足。

mysql innodb引擎 長時間使用後,資料檔案遠大於實際資料量,導致空間不足。

近期我碰到了一個令人頭疼的事情。就是我的mysql伺服器使用了很久之後,發現/data  目錄的空間佔滿了我係統的整個空間,馬上就要滿了。下面是我的分析。

在網上查看了這2個方法,但是執行後發現沒有解決。系統空間沒有變小。

1.optimize table table.name                                                    #後面發現這種方式只對MyISAM引擎的表格有用。

2.ALTER TABLE table.name ENGINE='InnoDB';                 #這種方式從原理上,感覺可以,但是我的測試並沒有成功。

所以繼續在網上查資料,並按整理下分析思路,最終解決:

ps -ef|grep mysql

root      1297     1  0 12:02 ?        00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data --pid-file=/var/run/mysqld/mysql5.pid
mysql     1412  1297  0 12:02 ?        00:00:01 /usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/data --user=mysql --log-error=/var/log/mysqld/mysql5-error.log --pid-file=/var/run/mysqld/mysql5.pid --socket=/var/run/mysqld/mysql5.socket --port=3306 

備份命令:

time=`date +%Y%m%d`
mysqldump -u root -p123456 -e --max_allowed_packet=16777216 --net_buffer_length=16384 my_data >/backup/my_data$time.sql

全庫備份大小:du -sh /backup/my_data$time.sql                      看到大小為150G

資料庫的大小:du -sh /data/my_data                                             看到457G

我經過多番研究,發現是innodb 為引擎的資料表,他的檔案大小是隻會增加而不會減小的,

例如你有1個表格裡面有約10000000條,大概10G的資料,但是你手動刪除了5000000條資料,即約5G的資料,但是刪除後,你會發現系統的空間還是佔用了10G,

如果需要減小他的大小隻有1種方式,就是重建資料庫或是資料表。

例如你執行下面語句可以查看錶格是否多佔用了空間: show table status like  ‘table_1%';

就會看到裡面有個 Data_free欄位,而他對應的值就是他多佔用的物理空間(61827186688),如果我們重建 或是重新匯入即可節省出空間(61827186688)。

mysql> show table status like 'table_1%';
+--------------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-------------+----------------+---------------------+-------------+------------+-----------------+----------+--------------------+---------+
| Name         | Engine | Version | Row_format | Rows     | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free   | Auto_increment | Create_time         | Update_time | Check_time | Collation       | Checksum | Create_options     | Comment |
+--------------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-------------+----------------+---------------------+-------------+------------+-----------------+----------+--------------------+---------+
| table_1      | InnoDB |      10 | Compact    | 43626792 |            478 | 20884504576 |               0 |   3810557952 | 61827186688 |      527273346 | 2013-01-21 18:58:58 | NULL        | NULL       | utf8_unicode_ci |     NULL | row_format=COMPACT |         |
+--------------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-------------+----------------+---------------------+-------------+------------+-----------------+----------+--------------------+---------+
2 rows in set (1.41 sec)

因為我的系統對mysql 做了獨立表空間,所以我可以看到各個表佔用的系統空間。

[[email protected] ~]# du -sh /data/my_data/* |grep G
66G     /data/my_data/table_1.ibd
64G    /data/my_data/table_2.ibd
106G     /data/my_data/table_3.ibd
84G    /data/my_data/table_4.ibd

經過我的仔細檢視發現,原來我的資料庫裡面有4個表格是大於60G的  還有1個是100G的,通過上面這個方式檢視,data_free下面的值非常大,所以我在測試環境測試後,發現沒有問題。

如果你的系統是預設的,沒做獨立表空間,即在/etc/my.conf 這個檔案中沒有新增這一條innodb_file_per_table=1;那麼你就只能用show table status like 'table%'; 一個一個表格去檢視 Data_free欄位,找出可以恢復空間的表格。

然後進行下面操作:

#到處可以恢復系統空間的表格。

mysqldump -uroot -p123456  my_data table_1 >/mnt/table_1.sql 

#登入資料庫

mysql -uroot -p123456   

#選擇資料庫                                                                       

use my_data;              

#刪除可恢復空間的表格,即data_free值很大的                                                                        

drop table table_1.sql;      

  #恢復表格                                                            

source /mnt/table_1.sql;           

#對比恢復前後的狀態                                                     

show table status like 'table_1%';                                                    

對比和之前狀態一直,然後檢視系統,發現系統的空間恢復了幾十G,如此對幾個大的表格都做了如上操作,磁碟不能回收的問題解決。

此處之所以進行多次對錶的備份和恢復,是因為我的業務不允許停機,所以只能進行單表操作。

如果你的系統的業務允許你在一段時間都停止服務的話,建議備份整個資料庫,然後清空,重建/data  目錄,然後恢復整個資料庫。

如果最後你發現自己的沒做獨立表空間,那麼你就只能對整個資料庫做個全庫備份,然後重建/data目錄,然後恢復整個資料庫。

20140327 今天空間又不足了,經過多次試驗得出結論。

原來對於InnoDB 通過該命令還是有用的,”OPTIMIZE TABLE  my_table1“。

使用方式如下:

1.首先檢視可以釋放空間的表格有哪些,其中data_free項有值的表是可以釋放空間的。

#select table_name,data_free,engine from information_schema.tables where table_schema='house_radar';

+----------------------------+-------------+--------+
| table_name                 | data_free   | engine |
+----------------------------+-------------+--------+
| xixi_test2                 | 10108272640 | InnoDB |
| xixi_test1                 | 12522094592 | InnoDB |
| haha_back            |    17825792    | InnoDB |
| haha_list                 |           0 | InnoDB |
| haha_list_2            |           0 | InnoDB |
| haha_rest               |           0 | InnoDB |
| haha_type_list       |           0 | InnoDB |
| wawa_list               |           0| InnoDB |
| borker_haha          |           0| InnoDB |
| broker_data           |           0 | MyISAM |
| jiajia_test2             | 18768461824 | InnoDB |
| jiajia_test1             |     6291456 | InnoDB |

此處data_free 欄位顯示的單位是位元組,如  xixi_test2,10108272640/1024/1024/1024=9.4G,所以理論上釋放後是可以恢復9.4G的空間的。

2.檢視下單個表的data_free大小

#show table status like 'xixi_test2';

3.執行該命令,執行後檢視磁碟空間,發現下空間果然變小了。 

#OPTIMIZE TABLE xixi_test2;

其次,該命令執行完畢後,返回命令,雖然提示不支援,optimize,但是已經進行重建和分析,空間已經回收。

+-------------+----------+----------+-------------------------------------------------------------------+
| Table        | Op        | Msg_type | Msg_text                                                          |
+-------------+----------+----------+-------------------------------------------------------------------+
| xixi_test2 | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| xixi_test2 | optimize | status  | OK                                                               |
+-------------+----------+----------+-------------------------------------------------------------------+

執行前後:

/dev/sdb1               503960    455150     23212  96% /home/mysql
/dev/sdb1               503960    452495     25866  95% /home/mysql

注意:該操作執行的時候會把該表格先寫入一個tmp臨時表,所以如果你要釋放的那個表格是10G,那麼你的磁碟必須還有10G的空餘空間,否則會執行失敗。