目前系統的 Stat 表以每天 20W 條的資料量增加,儘管已經把超過3個月的資料 dump 到其他地方,但表中仍然有接近 2KW 條資料,容量接近 2GB。
Stat 表已經加上索引,直接 select … where … limit 的話,速度還是很快的,但一旦涉及到 group by 分頁,就會變得很慢。
據觀察,7天內的 group by 需要 35~50s 左右。運營反映體驗極其不友好。 於是上網搜尋 MySQL 分割槽方案。發現網上的基本上都是在系統性地講解 partition 的概念和種類,以及一些實驗性質的效果,並不貼近實戰。
通過參考 MySQL手冊以及自己的摸索,最終在當前系統中實現了分割槽,因為記錄一下。
分割槽型別的選擇
Stat 表本身是一個統計報表,所以它的資料都是按日期來存放的,並且熱資料一般只限於當天,以及7天內。所以我選擇了 Range 型別來進行分割槽。
為當前表建立分割槽
因為是對已有表進行改造,所以只能用 alter 的方式:
ALTER TABLE stat
PARTITION BY RANGE(TO_DAYS(dt)) (
PARTITION p0 VALUES LESS THAN(0),
PARTITION p190214 VALUES LESS THAN(TO_DAYS('2019-02-14')),
PARTITION pm VALUES LESS THAN(MAXVALUE)
);
複製程式碼
這裡有2點要注意:
一是 p0 分割槽,這是因為 MySQL(我是5.7版) 有個 bug,就是不管你查的資料在哪個區,它都會掃一下第一個區,我們每個區的資料都有幾十萬條,掃一下很是肉疼啊,所以為了避免不必要的掃描,直接弄個0資料分割槽就行了。
二是 pm 分割槽,這個是最大分割槽。假如不要 pm,那你存 2019-02-15 的資料就會報錯。所以 pm 實際上是給未來的資料一個預留的分割槽。
定期擴充套件分割槽
由於 MySQL 的分割槽並不能自己動態擴容,所以我們要寫個程式碼為它動態的增加分割槽。
增加分割槽需要用到 REORGANIZE
命令,它的作用是對某個分割槽重新分配。
比如明天是 15 號,那我們要給 15 號也增加個分割槽,實際上就是把 pm 分割槽拆分成2個分割槽:
ALTER TABLE stat
REORGANIZE PARTITION pm INTO (
PARTITION p190215 VALUES LESS THAN(TO_DAYS('2019-02-15')),
PARTITION pm VALUES LESS THAN(MAXVALUE)
);
複製程式碼
這裡就涉及到一個問題,即如何獲得當前表的所有分割槽?網上有挺多方法,但我試了下感覺還是先 show create table stat
然後用正則匹配出所有分割槽更方便一點。
定期刪除分割槽
隨著資料庫越來越大,我們肯定是要清除舊的資料,同時也要清除舊的分割槽。 這個也比較簡單:
ALTER TABLE stat DROP PARTITION p190214, p190215
複製程式碼