目前系統的 Stat 表以天天 20W 條的數據量增長,儘管已經把超過3個月的數據 dump 到其餘地方,但表中仍然有接近 2KW 條數據,容量接近 2GB。sql
Stat 表已經加上索引,直接 select … where … limit 的話,速度仍是很快的,但一旦涉及到 group by 分頁,就會變得很慢。數據庫
據觀察,7天內的 group by 須要 35~50s 左右。運營反映體驗極其不友好。 因而上網搜索 MySQL 分區方案。發現網上的基本上都是在系統性地講解 partition 的概念和種類,以及一些實驗性質的效果,並不貼近實戰。spa
經過參考 MySQL手冊以及本身的摸索,最終在當前系統中實現了分區,由於記錄一下。code
Stat 表自己是一個統計報表,因此它的數據都是按日期來存放的,而且熱數據通常只限於當天,以及7天內。因此我選擇了 Range 類型來進行分區。索引
由於是對已有表進行改造,因此只能用 alter 的方式:string
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點要注意:it
一是 p0 分區,這是由於 MySQL(我是5.7版) 有個 bug,就是無論你查的數據在哪一個區,它都會掃一下第一個區,咱們每一個區的數據都有幾十萬條,掃一下非常肉疼啊,因此爲了不沒必要要的掃描,直接弄個0數據分區就好了。io
二是 pm 分區,這個是最大分區。假如不要 pm,那你存 2019-02-15 的數據就會報錯。因此 pm 其實是給將來的數據一個預留的分區。table
因爲 MySQL 的分區並不能本身動態擴容,因此咱們要寫個代碼爲它動態的增長分區。class
增長分區須要用到 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
複製代碼