如果MySQL數據庫實例的磁盤空間滿,會導致實例變為只讀狀態,寫業務夯住,應用無法對數據庫進行寫入操作,從而影響業務正常運行。本文介紹查看空間使用情況的方式,以及各種空間問題的原因和解決方案。
查看空間使用情況
您可以在實例管理的基本信息頁面查看存儲空間和備份空間的使用情況,這里只展示當前的空間使用總量,沒有展示各類數據分別占用的磁盤空間信息,也沒有空間使用的歷史信息。
您還可以在實例詳情頁面,查看目標實例的磁盤空間使用的歷史信息和變化曲線。
Binlog日志文件占用過多
原因及現象:
默認binlog日志是保留7天,如果是在遷移大量數據,實例磁盤空間太小的話,會短時間內產生大量的binlog導致磁盤空間不足。
解決方案:
MySQL Binlog日志文件占用過多,可以在mysql命令行上使用PURGE BINARY LOGS BEFORE '2023-06-26 10:00:00'或者PURGE BINARY LOGS TO 'mysql-bin.010'來臨時清理本地binlog日志,釋放磁盤空間,或者臨時修改實例expire_logs_days參數。
表上的索引太多導致空間不足
原因及現象:
通常表上除了主鍵索引,還存在二級索引,二級索引越多,整個表空間就越大。
解決方案:
優化數據結構,減少二級索引的數量,合并索引建立聯合索引等。
大字段導致空間不足
原因及現象:
如果表結構定義中有blob、text等大字段或很長的varchar字段,也會占用更大的表空間。
解決方案:
優化表數據結構,壓縮數據后再插入。
表空間碎片太多導致空間不足
原因及現象:
空閑表空間太多到最后InnoDB表的碎片率高。InnoDB是按頁(Page)管理表空間的,如果Page寫滿記錄,然后部分記錄又被刪除,后續這些刪除的記錄位置又沒有新的記錄插入,就會產生很多空閑空間。MySQL 的表在進行了長時間多次 delete 、update 和 insert 后,表空間會出現碎片。定期進行表空間整理,消除碎片可以提高訪問表空間的性能。
解決方案:
使用以下命令可以找出表空間中可釋放空間超過100M的最大10個表:
mysql> select table_name,round(data_length/1024/1024) as data_length_mb, round(data_free/1024/1024) as data_free_mb
from information_schema.tables where round(data_free/1024/1024) > 100 order by data_free_mb desc limit 10;
+------------+----------------+--------------+
| TABLE_NAME | data_length_mb | data_free_mb |
+------------+----------------+--------------+
| sbtest1 | 232 | 274 |
+------------+----------------+--------------+
1 row in set (0.02 sec)
使用 alter table ... force 進行表空間整理和 OPTIMIZE TABLE tablename命令的作用一樣,這個命令適用于 InnoDB , MyISAM 和 ARCHIVE 三種引擎的表。但是對于 InnoDB 的表,不支持 OPTIMIZE TABLE 命令,可以用 alter table sbtest1 engine=innodb 代替 ,在業務低峰期整理表空間。
mysql> OPTIMIZE TABLE sbtest1;
+----------------+----------+----------+-------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+----------------+----------+----------+-------------------------------------------------------------------+
| sbtest.sbtest1 | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| sbtest.sbtest1 | optimize | status | OK |
+----------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (1 min 25.24 sec)
mysql> alter table sbtest1 engine=innodb;
Query OK, 0 rows affected (1 min 3.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
臨時表空間過大導致空間不足
原因及現象:
半連接(Semi-join)、去重(distinct)、不走索引的order by等操作,會創建臨時表,如果涉及的數據量過多,可能導致臨時表空間過大。DDL操作重建表空間時,如果表特別大,創建索引排序時產生的臨時文件也會特別大。另外很多online DDL操作是不支持Instant算法而是通過創建新表實現的,DDL執行結束再刪除舊表,DDL過程中會同時存在兩份表。
解決方案:
可以查看explain執行計劃,確認是否包含Using Temporary 。大表DDL需要注意實例的空間是否足夠,不足的話請提前擴容磁盤。