作爲一個後端工程師,想必沒有人沒用過數據庫,跟我一起復習一下MySQL吧,本文是我學習《MySQL實戰45講》的總結筆記的第六篇,總結了MySQL的InnoDB引擎相關的實踐使用問題。
上一篇:MySQL核心知識學習之路(5)
1 MySQL爲什麼有時會"抖"一下?
啥是抖?
抖即不穩定,一個SQL語句平時速度挺快的,偶爾卻會慢一下,稱之爲“抖”
爲何會抖?
因爲InnoDB引擎在後臺刷“髒頁”佔用了IO資源。
所謂“髒頁”,就是當內存數據頁跟磁盤數據頁內容不一致的時候就是“髒頁”。
由於MySQL使用了WAL機制(Write-ahead logging 預寫式日誌),會將數據庫的隨機寫轉化爲順序寫,提高讀寫性能,但副作用就是“髒頁”
所謂“乾淨頁”,就是當內存數據寫入磁盤後,內存和磁盤上的數據頁的內容一致了。
抖的影響?
會造成系統不穩定,性能突然下降,對業務端不友好。
如何防抖?
(1)設置合理參數配置,如 innodb_io_capacity 設置成磁盤的IOPS值。
平時多關注髒頁比例(innodb_max_dirty_pages_pct,默認值75%),不要超過75%
2 爲何表數據刪掉一半後表文件大小不變?
表文件不變的原因?
因爲delete命令指示將記錄的位置 或 數據頁 標記爲了“可複用”,並沒有收回表空間
這些被標記爲“可複用”但還未被使用的空間被稱之爲“空洞”。
圖片來源:林曉斌《MySQL實戰45講》
使用delete命令刪除數據就會產生空洞,被標記爲“可複用”。而使用insert命令插入數據可能引起頁分裂,也可能產生空洞。
圖片來源:林曉斌《MySQL實戰45講》
表數據如何存放?
表數據既可以存放在共享表空間裏,也可以放在單獨的文件(.ibd)中。
由參數 innodb_file_per_table 控制:
-
= OFF,存放在系統共享表空間
-
= ON,存放在單獨的.ibd文件中
-
MySQL 5.6.6 開始,默認值就是ON
如何讓刪除數據後的表文件變小?
重建表,消除因爲進行大量的更新操作而產生的空洞。下圖是使用alter table t engine=InnoDB重建表的示意圖,MySQL 會自動完成轉存數據、交換表名、刪除舊錶的操作。
圖片來源:林曉斌《MySQL實戰45講》
如何正確重建表:
-
alter table t engine=InnoDB
-
optimize table t (等同於 recreate + analyze)
-
truncate table t (等同於 drop + create)
Online DDL
MySQL 5.6開始引入了Online DDL,支持在重建表過程中對錶做更新操作。
圖片來源:林曉斌《MySQL實戰45講》
其實現原理如下:
-
在生成臨時文件過程中,通過row log記錄更新操作,然後再應用到臨時文件。
-
最後用臨時文件整體替換表的數據文件。
-
alter語句在啓動時獲取MDL寫鎖,但在真正拷貝數據之前退化爲MDL讀鎖,而MDL讀鎖不會阻塞更新操作。
適用場景:可以考慮在業務低峯期使用。
在MySQL 5.5及之前版本,這個命令會阻塞DML。
3 count(*)爲何這麼慢?
不同引擎對於count(*)的實現方式
select count(*) from t
MyISAM引擎將表的總行數存在了磁盤上,因此效率很高
InnoDB引擎則每次都需要將數據一行一行地從引擎中讀出來進行累積計數,因此存在性能問題。
那麼,問題來了:爲什麼InnoDB不跟MyISAM一樣設計?
InnoDB的事務隔離級別默認是可重複讀,而MyISAM不支持事務
那麼,第二個問題:能用show table status中的TABLE_ROWS代替嗎?
不能,因爲它是通過採樣估算的,存在40%~50%的誤差。
自己計數的實現方法
方式1:用緩存系統如Redis來保存計數,存在丟失更新、邏輯上不精確的問題,因此不建議使用。
方式2:用數據庫表來保存計數,不會丟失更新和不精確,建議使用。
不同count()用法對比
首先,弄清楚的count()的含義。
count():一個聚合函數,對於返回的結果集,一行行地判斷,如果count函數的參數不是NULL,累計值就加1,否則不加。最後返回累計值。
其次,直接給出結論。
按照效率排序:count(字段)<count(主鍵 id)<count(1)≈count(*)。
建議儘量使用 count(*),因爲MySQL對count(*)專門進行了優化。
4 小結
本文總結了MySQL的InnoDB引擎相關的實踐使用問題,包括MySQL爲什麼有時候會不穩定的“抖”一下、爲何表數據刪除了一半但表文件大小沒變 和 爲何 count(*)會很慢。
參考資料
林曉斌(丁奇),《MySQL實戰45講》
👇掃碼訂閱《MySQL實戰45講》