MySQL 你所不知的table is full那些事

2018-07-31 19:02 更新

當(dāng)我們要寫入新數(shù)據(jù)而發(fā)生“The table is full”告警錯誤時,先不要著急,按照下面的思路來逐步分析即可:
1、查看操作系統(tǒng)以及MySQL的錯誤日志文件
確認(rèn)操作系統(tǒng)的文件系統(tǒng)沒有報錯,并且MySQL的錯誤日志文件中是否有一些最直觀的可見的錯誤提示。
有可能是數(shù)據(jù)庫文件超過操作系統(tǒng)層的文件大小限制,比如fat/fat32以及低版本的Linux,文件最大不可以大于2G(最大擴(kuò)展到4G),這就需要轉(zhuǎn)換fat32為NTFS,或升級Linux版本。

2、確認(rèn)磁盤空間沒有滿
執(zhí)行 df -h 查看剩余磁盤空間,如果發(fā)現(xiàn)磁盤空間確實(shí)已經(jīng)用完,則盡快刪除不需要的文件。

如果通過 du 計算各個目錄的總和卻發(fā)現(xiàn)根本不會用完磁盤空間時,就需要注意了,可能是某個被刪除的文件還沒完全釋放,導(dǎo)致 df 看起來已經(jīng)用完,但 du 卻又統(tǒng)計不到。
這時候可以執(zhí)行 lsof | grep -i deleted 找到被刪除的大文件,將其對應(yīng)的進(jìn)程殺掉,釋放該文件描述符。

如果該進(jìn)程不能被殺掉,例如是 mysqld 進(jìn)程在占用的話,可以在 MySQL 里找到是哪個內(nèi)部線程在用,停止該線程即可。

曾經(jīng)發(fā)生過這樣一個例子:
用vim打開MySQL的slow query log,退出時選擇了 “wq” 指令,也就是保存退出,結(jié)果悲劇發(fā)生了。
因?yàn)樵谄浯蜷_的那段時間內(nèi),slow query log有新日志產(chǎn)生,會持續(xù)寫入,但他退出時采用保存退出的方式,變成了一個“新”文件(或者說新文件句柄 file handler),這個“新”文件無法被mysqld進(jìn)程識別,
mysqld進(jìn)程依舊將slow query log寫入到原來它打開的那個文件(或者說文件句柄)里,該日志文件在持續(xù)增長,但手工保存退出的文件卻再也不增長了,直接查看文件看不出任何異常。
這時候只能用 lsof -p pidof mysqld 才能看到該文件。
解決方法很簡單,將原來的文件備份一下,執(zhí)行下面的指令:

FLUSH SLOW LOGS;

備注:MySQL 5.5開始才支持 BINARY/ENGINE/ERROR/GENERAL/RELAY/SLOW 等關(guān)鍵字,之前的版本只能刷新全部日志。

3、確認(rèn)數(shù)據(jù)表狀態(tài)

  • 如果是MyISAM引擎

默認(rèn)配置下,MyISAM引擎最大可支持256TB(myisam_data_pointer_size = 6,256^6 = 256TB),除非操作系統(tǒng)層有限制。
在MySQL5.0中,MyISAM引擎行記錄默認(rèn)是動態(tài)長度,單表最大可達(dá)256TB,MyISAM行指針(myisam_data_pointer_size)長度為6字節(jié)。
在這之前,MyISAM行指針默認(rèn)長度為4字節(jié),只支持4GB的數(shù)據(jù)。改行指針最大值可設(shè)為8字節(jié)。
在行指針設(shè)置較小不夠用的時候,為提高M(jìn)yISAM表最大容量,可以修改表定義設(shè)定MAX_ROWS的值:

ALTER TABLE `xx` ENGINE=MyISAM MAX_ROWS=_nn_

備注:表定義中,AVG_ROW_LENGTH 屬性定義的是 BLOB/TEXT 字段類型的最大長度。

  • 如果是InnoDB引擎

ibdata共享表空間最后一個文件沒有設(shè)置成自增長,或者超過32位系統(tǒng)的單文件大小限制。
解決方法:
1、ibdata
的最后一個文件(非最后一個文件無法設(shè)置為自動增長)設(shè)置成自動增長;
2、檢查操作系統(tǒng),遷移到64位操作系統(tǒng)下;
3、轉(zhuǎn)成獨(dú)立表空間;
4、刪除歷史數(shù)據(jù),重整表空間;

  • 如果是MEMORY引擎

1、適當(dāng)提高max_heap_table_size設(shè)置(注意該值是會話級別,不要設(shè)置過大,例如1GB,一般不建議超過256MB);
2、執(zhí)行ALTER TABLE t_mem ENGINE=MEMORY; 重整表空間,否則無法寫入新數(shù)據(jù);
3、刪除部分歷史數(shù)據(jù)或者直接清空,重整表空間;
4、設(shè)置 big_tables = 1,將所有臨時表存儲在磁盤,而非內(nèi)存中,缺點(diǎn)是如果某個SQL執(zhí)行時需要用到臨時表,則性能會差很多;

順便說下,如果數(shù)據(jù)表有一列自增INT做主鍵,但是該ID值達(dá)到了INT最大值的話,MyISAM、MEMORY、InnoDB三種引擎的告警信息是不一樣的。
InnoDB引擎的告警信息類似這樣:
ERROR 1467 (HY000): Failed to read auto-increment value from storage engine

而MyISAM和MEMORY引擎則都是這樣:
ERROR 1062 (23000): Duplicate entry ‘4294967295’ for key ‘PRIMARY’

參考

MySQL手冊:B.5.2.12 The table is full

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號