環境資訊
1、主控端:Ubuntu 20.04.2 LTS
2、Docker: 20.10.6
3、鏡像版本: mysql:5.7.19
簡述
上一節,在《Docker容器MySQL5.7系統表空間資料檔案ibdata1》 中,分析如何使用 innochecksum 工具來分析了什麼被存儲到了 ibdata1 裡。我們發現 Undo log page 占據了 ibdata1 中 93% 的空間。
那麼,有什麼辦法回收已使用的空間嗎?
沒有,目前還沒有一個容易并且快速的方法。InnoDB 表空間從不收縮...
當你删除一些行,這個頁被标為已删除稍後重用,但是這個空間從不會被回收。唯一的方法是使用新的 ibdata1 啟動資料庫。要做這個你應該需要使用 mysqldump 做一個邏輯全備份,然後停止 MySQL 并删除所有資料庫、
、
ib_logfile*
ibdata*
檔案。當你再啟動 MySQL 的時候将會建立一個新的共享表空間。然後恢複邏輯備份。
不過 Docker 的話,還是删除整個檔案夾再重建一個新的空檔案夾更友善,否則重新開機容器時,會因為 datadir 不為空,導緻無法正常初始化而失敗。
0.前置準備
★ 重新開機服務: 首先,我們把 Docker 容器的 MySQL 服務停掉了,現在我們先重新拉起:
docker ps -a
docker restart 容器ID
★ 登入容器 Bash: 然後,再次登入 Docker 容器的 Bash:
docker container exec -it 容器ID /bin/bash
因為我們的主機沒有安裝對應 MySQL 軟體,是以登入容器執行。
1.邏輯全備份
cd /var/lib/mysql
mysqldump -uroot -p --add-drop-table --all-databases > all.sql
/var/lib/mysql
是 MySQL 目前的 datadir 資料檔案路徑。
-
備份所有的資料庫。--all-databases
-
在所有的 CREATE 語句前加上 DROP 語句。--add-drop-table
- 那為什麼要添加
呢?是為了解決權限問題。-uroot -p
-
是輸出重定向符号,表示将左邊的内容輸出到右邊的檔案中。>
2.清除并重建資料檔案
清除之前,建議停止目前 Docker 容器:
docker stop 容器ID
然後 cd 進入在Docker容器之
/var/lib/mysql
在 主控端的映射檔案夾下:
比如我用
docker container inspect
檢視到我的主控端映射目錄是
/var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data
docker container inspect 容器ID | grep Mounts -A 20
★ 先把 all.sql 轉移走
cd /var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data
mv all.sql ~/
★ 移除 _data 檔案夾
cd /var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/
rm -rf _data/
mkdir _data
★ 再把 all.sql 放回映射的資料檔案夾
cd /var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data
mv ~/all.sql ./
然後,重新開機 Docker 服務。重複 0.前置準備 中的操作,當你再啟動 MySQL 的時候将會建立一個新的共享表空間。
我們可以對比一下 ibdata1 的大小變化,首先是重建前:
然後,是重建後:
3.恢複邏輯全備份
再次進入 Docker 中的 MySQL 容器 Bash 中:
cd /var/lib/mysql
mysql -uroot -p < all.sql
備份恢複之後,就可以删除 all.sql 了。
參考文檔
1、《解決ibdata1資料庫過大的問題》
2、《MySQL的ibdata1詳解》