MySQL 中刪除的數據都去哪兒了?


不知道大家有沒有想過下面這件事?

我們平時調用 DELETE 在 MySQL 中刪除的數據都去哪兒了?

這還用問嗎?當然是被刪除了啊

那么這里又有個新的問題了,如果在 InnoDB 下,多事務並發的情況下,如果事務A刪除了 id=1 的數據,同時事務B又去讀取 id=1 的數據,如果這條數據真的被刪除了,那 MVCC 拿啥數據返回給用戶呢?

沒錯,這就需要了解一下 MySQL 的多版本並發的原理相關的東西,感興趣的可以去看我之前寫的這篇文章

所以,實際情況中,調用了 DELETE 語句刪除的數據並不會真正的被物理刪除,這條數據其實還在那,只不過被打上了一個標記,標記已刪除

這其實跟我們日常的操作——軟刪除,差不多是一個意思

在 MySQL 中, UPDATEDELETE 操作本質上是一樣的, 都屬於更新操作,刪除操作只不過是把某行數據中的一個特定的比特位標記為已刪除,僅此而已。

那么問題又來了,那這些刪除的數據如果一直這么堆下去,那不早晚把硬盤撐爆?

如果都玩兒成這樣了,那 MySQL 還能像現在這樣被大規模的用於生產環境中嗎?那 MySQL 到底是怎么玩的?

這就需要提到 Purge 操作了。

Purge操作是啥?

Purge 操作才是真正將數據(已被標記為已刪除)物理刪除的操作。

Purge 操作針對的數據對象,不僅僅是某一行,還有其對應的索引數據和 Undo Log。

好的那么問題又來了。

問題是,Purge 操作什么時候會執行呢?實際上,你可以將執行 Purge 操作的線程(簡稱 Purge 線程)理解成一個后台周期性執行的線程。

Purge 線程可以有一個,也可以有多個,具體的線程數量可以由 MySQL 的配置項 innodb_purge_threads 來進行配置。當然,我相信你肯定不記得在使用 MySQL 的時候配置過這個,因為 innodb_purge_threads 有個默認值,值為 4

InnoDB 會根據 MySQL 中表的數量和 Purge 線程的數量進行分配。

但正是因為有這種特性,Purge 線程的數量才需要根據業務的實際情況來做調整。舉個例子,假設 DML 操作都集中在某張表,比如表1上...

你先等等,我打斷一下......

什么叫 DML 操作?總喜歡搞些復雜的名詞...DML(Data Manipulation Language)數據操作語句,實際上就是CRUD增刪改查...

與之類似的概念還有DDL(Data Definition Language)數據定義語句,也就是CREATEDROPALTER等等.

以及DCL(Data Control Language)數據控制語句,也就是GRANTREVOKE等等...

繼續說回來,雖然 Purge 線程的數量是可配置的,但是也不是你想配多少就配多少的。不然你給它干個 10000 個線程,那不就直接原地 OOM 了嗎?

innodb_purge_threads 的最大值為 32,而且並不是我們配了 32 InnoDB 就真的會啟動 32 個 Purge 線程,為啥呢?舉個很簡單的例子,假設此時只有一張表,然后我們配置了 32 個 Purge 線程。

你看着上面這個圖問問自己,這「河里」嗎?這樣不僅浪費了系統的資源,同時還使得不同的 Purge 線程之間發生了數據競爭。不僅如此,Purge 線程還可能跟用戶線程產生競爭。

但是當系統中真的有 32 張表的時候,情況又不一樣了,一個 Purge 線程對應一張表,線程與線程之間就不會存在數據競爭,並且沒有浪費系統資源,還能夠提升執行 Purge 操作的性能。

這就是為啥 InnoDB 會根據實際情況來調整 MySQL 中 Purge 線程的數量,所以我們在配置的時候也要按照實際情況來設置。

舉個例子,如果你的數據庫中,增刪改 的操作只集中在某幾張表上,則可以考慮將 innodb_purge_threads 設置的稍微低一點。相反,如果 增刪改 的操作幾乎每張表都有,那么 innodb_purge_threads 就可以設置的大一些。

了解完 Purge 線程本身之后,我們就可以來了解 Purge 線程所針對的對象了。Purge 線程主要清理的對象是 Undo Logs,其次是行記錄。

因為 Undo Log 可以分為:

  • Insert Undo Log
  • Update Undo Log

所以更准確的說法是,Purge 線程清理的對象是 Update Undo Log 和 行記錄,因為 Insert Undo Log 會在事務提交之后就會被刪除。

我們都知道 InnoDB 的 MVCC 的數據來源是一個一個 Undo Log 形成的單鏈表,而 Purge 線程就是用於定期清理 Undo Log 的,並且在清理完 刪除數據所生成的 Undo Log 的時候,就會把對應的行記錄給移除了。

那么問題又來了,Purge 線程每次會讀取多少條件 Undo Log 記錄呢?

很明顯,它不是看當時的心情來決定取多少條的。它是通過配置項 innodb_purge_batch_size 來控制的,默認是 300。然后InnoDB會將這300條 Undo Log 分給innodb_purge_threads個 Purge 線程。在清理的過程中,Purge 線程還會釋放 Undo Log 表空間內的文件。

本篇文章已放到我的 Github github.com/sh-blog 中,歡迎 Star。微信搜索關注【SH的全棧筆記】,回復【隊列】獲取MQ學習資料,包含基礎概念解析和RocketMQ詳細的源碼解析,持續更新中。

如果你覺得這篇文章對你有幫助,還麻煩點個贊關個注分個享留個言


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM