共計 6383 個字符,預計需要花費 16 分鐘才能閱讀完成。
本篇內容主要講解“MySQL 的碎片有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“MySQL 的碎片有哪些”吧!
MySQL 的幾種碎片整理方案總結(解決 delete 大量數據后空間不釋放的問題)1. 背景知識?1.1 為什么會有碎片?
MySQL 中 insert 與 update 都可能導致頁分裂,這樣就存在碎片。
對于大量的 UPDATE,也會產生文件碎片化,Innodb 的最小物理存儲分配單位是頁(page),而 UPDATE 也可能導致頁分裂(page split),頻繁的頁分裂,頁會變得稀疏,并且被不規則的填充,所以最終數據會有碎片。
delete 語句實際上只是給數據打個標記,并且記錄到一個鏈表中,這樣就形成了留白空間。
在 InnoDB 中,刪除一些行,這些行只是被標記為“已刪除”,而不是真的從索引中物理刪除了,因而空間也沒有真的被釋放回收。InnoDB 的 Purge 線程會異步的來清理這些沒用的索引鍵和行。
當執行插入操作時,MySQL 會嘗試使用空白空間,但如果某個空白空間一直沒有被大小合適的數據占用,仍然無法將其徹底占用,就形成了碎片;
總結:
truncate table 其實有點類似于 drop table 然后 creat, 只不過這個 create table 的過程做了優化,比如表結構文件之前已經有了等等。所以速度上應該是接近 drop table 的速度;
drop,truncate 立刻釋放磁盤空間,不管是 Innodb 和 MyISAM ;
delete from table_name 刪除表的全部數據, 對于 MyISAM 會立刻釋放磁盤空間(應該是做了特別處理,也比較合理),InnoDB 不會釋放磁盤空間;
對于 delete from table_name where xxx; 帶條件的刪除, 不管是 innodb 還是 MyISAM 都不會釋放磁盤空間;
delete 操作以后使用 optimize table table_name 會立刻釋放磁盤空間。不管是 innodb 還是 myisam。所以要想達到釋放磁盤空間的目的,delete 以后執行 optimize table 操作。
delete from 表以后雖然未釋放磁盤空間,但是下次插入數據的時候,仍然可以使用這部分空間。
表的增刪改操作,可能會造成數據空洞的,當對表進行大量的增刪改操作后,數據空洞存在的可能性比較大。
MySQL 刪除數據幾種情況以及是否釋放磁盤空間:
1.2 碎片帶來的問題
當 MySQL 對數據進行掃描時,它掃描的對象實際是列表的容量需求上限,也就是數據被寫入的區域中處于峰值位置的部分;
MySQL 數據庫中的表在進行了多次 delete、update 和 insert 后,表空間會出現碎片。定期進行表空間整理,消除碎片可以提高訪問表空間的性能。
這種碎片不僅額外增加了存儲代價,同時也因為數據碎片化降低了表的掃描效率。
碎片若不整理,那么可能會長期占據磁盤空間,導致磁盤使用率越來越高。
2. 如何清理碎片?
修復問題的前提是要先找到問題,這樣才能對癥下藥。
2.1. 查看表的碎片情況
查看數據庫中每個存在碎片的表
mysql select concat(optimize table ,table_schema, . ,table_name,),data_free,engine from information_schema.tables where data_free 0 and engine != MEMORY
+-----------------------------------------------------------+-----------+--------+
| concat(optimize table ,table_schema, . ,table_name,) | DATA_FREE | ENGINE |
+-----------------------------------------------------------+-----------+--------+
| optimize table abc.t_user_answer; | 2097152 | InnoDB |
| optimize table mysql.time_zone_transition; | 4194304 | InnoDB |
| optimize table mysql.time_zone_transition_type; | 4194304 | InnoDB |
| optimize table mysql.user; | 4194304 | InnoDB |。。。。
查看指定表的碎片情況
mysql show table status like t_user \G
*************************** 1. row ***************************
Name: t_user
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 4333
Avg_row_length: 589
Data_length: 2555904
Max_data_length: 0
Index_length: 2719744
Data_free: 4194304
Auto_increment: NULL
Create_time: 2021-11-19 10:13:31
Update_time: 2022-04-20 14:28:42
Check_time: NULL
Collation: utf8mb4_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
Data_free: 4194304 就代表碎片的 byte 數。如果經常刪改數據表,會造成大量的 Data_free 頻繁 刪除記錄 或修改有可變長度字段的表。
找到碎片化最嚴重的表
SELECT table_schema, TABLE_NAME, concat(data_free/1024/1024, M) as data_free
FROM `information_schema`.tables
WHERE data_free 3 * 1024 * 1024
AND ENGINE = innodb
ORDER BY data_free DESC
2.2 清理碎片 (回收空間) 的方法
官方文檔參考
通常有這幾種做法
alter table tb_test engine=innodb;(本質上是 recreate)
optimize table tb_test;(本質上是 recreate,但是在不同創建下會有區別)
ALTER TABLE tablename FORCE (在 InnoDB 表中等價于 alter table tb_test engine=innodb;)
mysqlcheck 批量表空間優化
gh-ost/pt-osc
pt-online-schema-change(本質上也是 先備份舊表數據,然后 truncate 舊表)
1. alter table tb_test engine=innodb 原理介紹
這其實是一個 NULL 操作, 表面上看什么也不做, 實際上重新整理碎片了. 當執行優化操作時, 實際執行的是一個空的 ALTER 命令, 但是這個命令也會起到優化的作用, 它會重建整個表, 刪掉未使用的空白空間.
Running ALTER TABLE tbl_name ENGINE=INNODB on an existing InnoDB table performs a“null”ALTER TABLE operation, which can be used to defragment an InnoDB table, as described in Section 15.11.4,“Defragmenting a Table”. Running ALTER TABLE tbl_name FORCE on an InnoDB table performs the same function.
MySQL5.6 開始采用 Inplace 方式重建表,Alter 期間,支持 DML 查詢和更新操作,語句為 alter table t engine=innodb, ALGORITHM=inplace; 之所以支持 DML 更新操作,是因為數據拷貝期間會將 DML 更新操作記錄到 Row log 中。 重建過程中最耗時的就是拷貝數據的過程,這個過程中支持 DML 查詢和更新操作,對于整個 DDL 來說,鎖時間很短,就可以近似認為是 Online DDL。 執行過程: 1、獲取 MDL(Meta Data Lock)寫鎖,innodb 內部創建與原表結構相同的臨時文件
2、拷貝數據之前,MDL 寫鎖退化成 MDL 讀鎖,支持 DML 更新操作
3、根據主鍵遞增順序,將一行一行的數據讀出并寫入到臨時文件,直至全部寫入完成。并且,會將拷貝期間的 DML 更新操作記錄到 Row log 中
4、上鎖,再將 Row log 中的數據應用到臨時文件
5、互換原表和臨時表表名
6、刪除臨時表
2. optimize table xxx;
OPTIMIZE TABLE 語句可以重新組織表、索引的物理存儲,減少存儲空間,提高訪問的 I / O 效率。類似于碎片整理功能。
MySQL 可以通過 optimize table 語句釋放表空間,重組表數據和索引的物理頁,減少表所占空間和優化讀寫性能
使用語法
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_n 說 ame [, tbl_name] …
對于主從架構,LOCAL 參數可以讓這個過程不寫入 binlog , 這樣在主庫上執行時就不會同步給從庫了
默認情況下,MySQL 將 OPTIMIZE TABLE 語句寫入二進制日志,以便它們復制到 slave 服務器。如果不想寫二進制日志,使用命令時加上 NO_WRITE_To_BINLOG 或 LOCAL 關鍵字即可。
使用這個語句需要具有對目標表的 SELECT、INSERT 權限。
注意:
需要有足夠的空間才能進行 OPTIMIZE TABLE。(剩余空間必須 被 OPTIMIZE 的表的大小)
OPTIMIZE 只對獨立表空間 (innodb_file_per_table=1) 才有用,對共享表空間不起作用。
對于共享表空間,如果需要瘦身:必須將數據導出,刪除 ibdata1,然后將 innodb_file_per_table 設置為獨立表空間,然后將數據導入進來。
對于 InnoDB 的表,OPTIMIZE TABLE 的工作原理如下
對于 InnoDB 表,OPTIMIZE TABLE 映射到 ALTER TABLE … FORCE(或者這樣翻譯:在 InnoDB 表中等價 ALTER TABLE … FORCE),它重建表以更新索引統計信息并釋放聚簇索引中未使用的空間。
當您在 InnoDB 表上運行時,它會顯示在 OPTIMIZE TABLE 的輸出中,如下所示:mysql OPTIMIZE TABLE foo;
+----------+----------+----------+---------------------------------------+
| Table | Op | Msg_type | Msg_text |
+----------+----------+----------+---------------------------------------+
| test.foo | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| test.foo | optimize | status | OK |
+----------+----------+----------+---------------------------------------+
# 但這個提示語可以忽略,從嚴格的意義講,說 InnoDB 不支持 optimize table,其實不太準確。 因為 MYSQL 的文檔說明了,當 INNODB 的表,MYSQL 會以 ALTER TABLE force + analyze 去執行這個命令(相當于做了 recreate 和 analyze)。 所以最終還是會看到 OK 的狀態。
# https://stackoverflow.com/questions/30635603/what-does-table-does-not-support-optimize-doing-recreate-analyze-instead-me
對于 MYISAM 表,OPTIMIZE TABLE 的工作原理:
1. 如果表已刪除或分隔行,就修復該表。
2. 如果索引頁沒有排序,就排序它們。
3. 如果表的統計信息不是最新的(而且修復不能通過對索引進行排序),就更新它們。
** 執行時也可以發現報錯:Temporary file write failure. **
建議參考這片文章:
Mysql optimize table 時報錯 Temporary file write failure. 的解決方案
optimize 語句的官網介紹
如果您已經刪除了表的一大部分,或者如果您已經對含有可變長度行的表(含有 VARCHAR, BLOB 或 TEXT 列的表)進行了很多更改,則應使用 OPTIMIZE TABLE。
被刪除的記錄被保持在鏈接清單中,后續的 INSERT 操作會重新使用舊的記錄位置。您可以使用 OPTIMIZE TABLE 來重新利用未使用的空間,并整理數據文件的碎片。
在多數的設置中,您根本不需要運行 OPTIMIZE TABLE。即使您對可變長度的行進行了大量的更新,您也不需要經常運行,每周一次或每月一次 即可,只對特定的表運行。
Mysql 5.6 之前 在 OPTIMIZE TABLE 運行過程中,MySQL 會鎖定表,5.6 之后有了 Online DDL 則大大減少了鎖表時間。
3. alter table、analyze table 和 optimize table 區別
alter table tb_test engine = innodb;
(也就是 recreate)MySQL 5.5 以前用 Offline 的方式重建表,5.6 以后用 Online 的方式重建表;
analyze table tb_test;
重新統計表的索引信息,不會修改數據,不會重建表,整個過程加 MDL 讀
optimize table tb_test;
是 alter table xxx = innodb;+ analyze table xxx; 的過程。
4. OPTIMIZE TABLE 和 ALTER TABLE xxxx ENGINE= INNODB 哪個更好
OPTIMIZE TABLE 還是 ALTER TABLE xxxx ENGINE= INNODB 基本上是一樣的。但是在有些情況下,ALTER TABLE xxxx ENGINE= INNODB 更好。
例如: old_alter_table 系統變量沒有啟用等等。
另外:對于 MyISAM 類型表,使用 ALTER TABLE xxxx ENGINE= INNODB 是明顯要優于 OPTIMIZE TABLE 這種方法的。
2.3 官方建議
MySQL 官方建議不要經常 (每小時或每天) 進行碎片整理,一般根據實際情況,只需要每周或者每月整理一次即可(我們現在是每月凌晨 4 點清理 mysql 所有實例下的表碎片)
到此,相信大家對“MySQL 的碎片有哪些”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!