關於MySQL資料被刪除後空間重用的問題實驗

2023-01-21 23:20:57 字數 1947 閱讀 1855

以前知道,mysql在通過delete語句刪除資料後,空間並不會被騰出,而只是在資料檔案中被標記為已刪除,除非執行optimize table。前兩天聽說,雖然delete資料後硬碟空間不會被騰出,但是在以後插入的行,會使用被刪除的資料的空間。換句話說,儘管硬碟空間沒有被騰出,新插入資料也不會受影響,因為他們根本不會使用剩餘的磁碟空間。這個在之前還真是從沒聽說過。

對於這個問題,我做了一個實驗,通過分析資料插入和刪除後ibd檔案的變化,來分析空間重用的情況。

建立表 :

create table `test` (

`id` int(10) unsigned not null auto_increment,

`a` varchar(30) not null,

primary key (`id`)

) engine=innodb default charset=latin1

行格式為預設的compact

第一步,插入資料:

先插入30條一樣的資料

insert into test (a) values (‘jwx’);

然後檢視test.ibd檔案

hexdump  -c -v test.ibd > tmp

可以看到,資料已經正常寫入,如截圖所示

因為只插入了30條資料,所以只佔用一個資料頁,這也是為了看起來方便。

根據上圖可以通過資料頁的page header 看出最後插入的位置的偏移量page_last_insert是 03 70,然後可以看到0xc370的位置就是最後一行所在的位置,如圖

同時可以看到,page_heap_top為03 84,指向0xc384,後面的內容就都是空閒空間了。

第二步,刪除一行資料

delete from test where id = 1

刪除id為1的資料

然後觀察ibd檔案

可以看到位於0xc079位置的數字變成了20,這是表示改行已被刪除,後面可以看到行索引id為 00 00 00 01,此時id為1的行已被刪除,同時可以注意到0xc08f到0xc091為 6a 77 78,這三個位元組即為’jwx’,行內容仍然保留著。然後page_heap_top保持不變,而page_last_insert則變為0x0000,大概是因為本次操作為delete(這個是猜的,不過和後面的結論關係不大)。

第三步,插入一行資料

insert into test (a) values (‘ss’)

觀察ibd檔案

可以看到,第一行的資訊有了明顯的變化,0xc078從03變成了02,該位元組表示本行變長欄位的長度,從03(’jwx’)變成了02(’ss’) 0xc08f到0xc091變成了73 73 78(‘ssx’),索引列欄位變成了00 00 00 1f(31),而page_last_insert則是00 7e,指向第一行的開頭,而不是堆頂,可以看出被刪除的資料空間被重用了。

通過上面的實驗可以看出mysql行被刪除後可以重用空間,其實在頁的page_header部分有一個page_free欄位就是用來記錄可重用空間的首指標位置的,0xc02c開始的兩個位元組即為page_free欄位。mysql官方文件是這樣描述這個欄位的:

當然,空間重用還有一個條件,就是被刪除的行長度至少要和新插入的行長度一樣,如果小於新插入的行,則空間就沒法重用了。

關於這個問題,stackoverflow上也有回答,詳情可以看以下連結

MySQL刪除資料後磁碟空間的釋放總結

1 drop table table name 立刻釋放磁碟空間 不管是 innodb和myisam 2 truncate table table name 立刻釋放磁碟空間 不管是 innodb和myisam truncate table其實有點類似於drop table 然後creat,只不過這...

MySQL刪除資料後磁碟空間的釋放總覽

1 drop table table name 立刻釋放磁碟空間 不管是 innodb和myisam 2 truncate table table name 立刻釋放磁碟空間 不管是 innodb和myisam truncate table其實有點類似於drop table 然後creat tabl...

Oracle表空間檔案被刪除後的處理方法

如果oracle 刪除表空間之前的時候你把表空間中的檔案也刪除了的話,這樣就會對我們的實際操產生一些不便,以下的文章就是對oracle 刪除表空間之前的時候你把表空間中的檔案也刪除在了的解決辦法的介紹。如果在清除表空間之前,先刪除了表空間對應的資料檔案,會造成資料庫無法正常啟動和關閉。可使用如下方法...