爲何刪除記錄表文件不會減少?(記錄的插入與刪除在磁盤上的變化)

若是你熟悉 MySQL 緩衝池(不熟悉能夠查看 一條 sql 的執行過程詳解),可能會以爲是由於刪除操做只更新到緩衝池和 redo log,並無進行 flush 落盤,但若是關閉數據庫,觸發 flush ,會發現表文件大小仍是不會改變,這是爲何?html

緣由

首先要了解數據的存儲方式,存儲方式共有兩種,是由參數 innodb_file_per_table 來控制的。算法

off:共享表結構,表示全部的文件數據存儲在同一個文件中,這樣在刪除整張表後空間也不會被回收,只是被位置被標記爲可重用,下次建立表可能就在該位置建立。sql

on:表示每張表的數據各用一個文件來存儲,在刪除整張表後該文件也會被回收,減少總佔用空間。這也是默認的使用方式。若是存儲引擎是 InnoDB ,那麼數據文件就是.ibd 格式的,若是是 MyISAM,那麼文件就是 .MYD 格式的。數據庫

 

雖然執行 drop 刪除表時會減少表文件大小,但在刪除記錄時仍是不能減少結構,這個緣由與上面的 off 共享表結構很像,由於 數據頁是 InnoDB 管理數據的最小的磁盤單位,數據頁就至關於上面的 "一張表的數據",由於一張表的數據頁都是存在同一個文件中的,因此在執行 delete 刪除數據後只會將將改位置標記可重用,並不會回收,而若是刪除整個頁,那麼也只能將該頁標記爲可重用而不會回收。這種刪除了可是沒有被回收的位置就稱爲 "數據空洞"。性能

頁合併與頁分裂

頁合併:既然產生了數據空洞,那麼數據文件將會變得愈來愈大,這樣是很不利的,因此 MySQL 會在數據空洞達到必定比例後出觸發 "頁合併",觸發的頁會找最靠近的能夠合併的頁進行合併來優化空間(只會將數據頁使用權騰出來,並不會減少表文件大小),防止後續的數據插入使用更多的數據頁形成文件更大。優化

頁分裂:頁分裂是在插入操做時操做的記錄主鍵 ID 在本來的記錄之間時產生的,由於記錄存儲在數據頁中,若是該數據頁沒有合適的位置來存儲這條記錄,那麼就會將該條記錄以及後面的記錄另開要一個數據頁來存儲。spa

優化:由於頁合併和頁分裂都須要消耗額外的性能。因此咱們在插入數據時應當按主鍵遞增順序插入(主鍵能夠使用自增ID 或 雪花算法,但若是業務字段有惟一字段且沒有其餘索引,那麼能夠使用其做爲主鍵來避免每次查詢都須要回表),刪除數據時按主鍵順序刪除。htm

 

如何減少表文件

一、自動觸發的頁合併。blog

二、手動觸發清理大部分的數據空洞(5.6 的 Online DDL 可能會存一些寫操做,可能會產生一些數據空洞),具體作法就是執行 "Alter table 表名 engine = InnoDB",由於 Alter 語句是修改表結構,而執行一個空修改操做就能夠在不修改結構的狀況下將數據空洞清除。具體原理是會先建立一個臨時表,將當前表中的全部記錄依次添加到臨時表中,最後再將臨時表替換原表的表。可是重建表並必定就是最緊湊的,由於在重建時每一個數據頁會留 1/16 用於更新,同時 5.6 後可能還會在向臨時表遷移數據時積累一些寫操做形成頁分裂。而在這過程當中不能有其餘操做干擾,好比修改數據、讀數據,因此在執行此操做時會添加 MDL 寫鎖,而在執行讀寫操做時會添加 MDL 讀鎖,二者互斥。索引

關於 MDL 鎖的解析可查看博客 Mysql 中的MDL 。

 

參考博客:

InnoDB中的頁合併與分裂

相關文章
相關標籤/搜索