學習記錄:MySQL碎片化的原因及解決方案?
底層知識
INNODB表的儲存
一個 InnoDB 表包含兩部分,即:表結構定義和資料。在 MySQL 8.0 版本以前,表結構是存在以 .frm 為字尾的檔案裡。而
MySQL 8.0 版本,則已經允許把表結構定義放在系統資料表中了。
表資料既可以存在共享表空間裡,也可以是單獨的檔案。這個行為是由引數innodb_file_per_table 控制的:
1. 這個引數設定為 OFF 表示的是,表的資料放在系統共享表空間,也就是跟資料字典放在一起;
2. 這個引數設定為 ON 表示的是,每個 InnoDB 表資料儲存在一個以 .ibd 為字尾的檔案中。
不需要這個表的時候,透過 drop table 命令,系統就會直接刪除這個檔案。
從 MySQL 5.6.6 版本開始,它的預設值就是 ON 。
資料處理流程
InnoDB的資料都是用B+樹的結構組織的。
刪除一條記錄,InnoDB引擎只會把記錄標記為刪除,之後如果插入資料是按照索引排序剛好落在這個區間內,可能會複用這個位置,但是磁碟檔案的大小不會縮小。
InnoDB的資料是按頁儲存的,如果刪掉一個資料頁上的所有記錄,整個資料頁會被複用。而記錄的複用是需要滿足範圍條件的,只有在範圍條件內的資料才會被複用。
如果相鄰的兩個資料頁利用率很小,系統會把兩個頁上的資料合併到其中一個頁上,另外的一個資料頁就被標記為可複用。
其實不止刪除資料會造成空洞,插入資料也會。
如果資料是按照索引遞增順序插入的,那麼索引是緊湊的。但如果資料是隨機插入的,就可能造成索引的資料頁分裂。
更新索引上的值,可以理解為刪除一箇舊的值,再插入一個新值。也會造出空洞!
經過大量增刪改的表,都是可能是存在空洞的。所以,如果能夠把這些空洞去掉,就能達到收縮表空間的目的。
碎片產生的原因
(1)表的儲存會出現碎片化,每當刪除了一行內容,該段空間就會變為空白、被留空,而在一段時間內的大量刪除操作,會使這種留空的空間變得比儲存列表內容所使用的空間更大;
(2)當執行插入操作時,MySQL會嘗試使用空白空間,但如果某個空白空間一直沒有被大小合適的資料佔用,仍然無法將其徹底佔用,就形成了碎片;
(3)當MySQL對資料進行掃描時,它掃描的物件實際是列表的容量需求上限,也就是資料被寫入的區域中處於峰值位置的部分;
重建表的方式處理碎片化
透過alter table A engine=InnoDB 命令來重建表。在 MySQL 5.5 版本之前,這個命令會自動完成轉存資料、交換表名、刪除舊錶的操作。
在往臨時表插入資料的過程中,有新資料寫入到A表,會造成資料丟失。這個操作不是Online的。
MySQL 5.6 版本開始引入的 Online DDL,重建表流程。
引入了 Online DDL 之後,重建表的流程:
1. 建立一個臨時檔案,掃描表 A 主鍵的所有資料頁;
2. 用資料頁中表 A 的記錄生成 B+ 樹,儲存到臨時檔案中;
3. 生成臨時檔案的過程中,將所有對 A 的操作記錄在一個日誌檔案( row log )中,對應的是圖中 state2 的狀態;
4. 臨時檔案生成後,將日誌檔案中的操作應用到臨時檔案,得到一個邏輯資料上與表 A 相同的資料檔案,對應的就是圖中 state3 的狀態;
5. 用臨時檔案替換表 A 的資料檔案。
在流程中,alter 語句在啟動的時候需要獲取 MDL 寫鎖,但是這個寫鎖 為了實現 Online,MDL 讀鎖不會阻塞增刪改操作。在真正複製資料之前就退化成讀鎖了。
那為什麼不乾脆直接解鎖呢?為了保護自己,禁止其他執行緒對這個表同時做 DDL 。
而對於一個大表來說, Online DDL 最耗時的過程就是複製資料到臨時表的過程,這個步驟的執行期間可以接受增刪改操作。所以,相對於整個 DDL 過程來說,鎖的時間非常短。對業務來說,就可以認為是 Online 的。
需要補充說明的是,上述的這些重建方法都會掃描原表資料和構建臨時檔案。對於很大的表來說,這個操作是很消耗 IO 和 CPU 資源的。因此,如果是線上服務,你要很小心地控制操作時間。如果想要比較安全的操作的話,我推薦你使用 GitHub 開源的 gh-ost 來做。
參考文章:丁奇,MySQL45講,13.為什麼表資料刪掉一半,表檔案大小不變?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69903557/viewspace-2749819/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mysql同步(複製)延遲的原因及解決方案MySql
- Mysql 非同步複製延遲的原因及解決方案MySql非同步
- Handler記憶體洩漏原因及解決方案記憶體
- 造成黏包的原因,及解決方案
- MySQL學習記錄MySql
- 碎片化的學習需要整理、沉澱,記錄到部落格是最好的方式!
- MYSQL資料庫表記錄刪除解決方案MySql資料庫
- 【記錄】MySQL 學習筆記MySql筆記
- [記錄] MySQL 學習筆記MySql筆記
- (Redis學習筆記):Redis解決方案Redis筆記
- nodejs埠被佔用原因及解決方案NodeJS
- SpringBoot整合Redis亂碼原因及解決方案Spring BootRedis
- Mysql Replication學習記錄MySql
- 網站內頁不收錄的原因及解決方法網站
- mysql的ERROR 1231 (42000)問題原因及解決方法MySqlError
- 碎片化的時代,如何學習
- JAVA記憶體洩露的原因及解決Java記憶體洩露
- No bean named 'xxx' is defined錯誤,原因及解決方案Bean
- 調節閥振動原因分析及解決方案
- 家庭電氣火災原因分析及解決方案
- spring.jackson.date-format失效原因及解決方案SpringORM
- JS定時器不可靠的原因及解決方案JS定時器
- 碎片化學習前端知識前端
- 碎片化學習Java大綱Java
- mysql忘記密碼解決方案MySql密碼
- Web 學習之跨域問題及解決方案Web跨域
- APP執行緩慢5個原因及解決方案APP
- 跨域的原因以及解決方案跨域
- CentOS 7 下Tomcat啟動超慢的原因及解決方案CentOSTomcat
- 解決golang 的記憶體碎片問題Golang記憶體
- 表碎片起因及解決辦法(zt)
- MySQL鞏固學習記錄(一)MySql
- Vue 前端跨域的解決方案(心得記錄)Vue前端跨域
- 碎片化學習Java(七)-- Java常量的使用Java
- 碎片化學習Java(十一)-- Java if案例Java
- 資料庫mysql學習筆記記錄資料庫MySql筆記
- 關於Allowed memory size of (PHP記憶體溢位)錯誤的可能原因及解決方案PHP記憶體溢位
- 強化學習-學習筆記11 | 解決高估問題強化學習筆記