MySQL 千萬級資料表 partition 實戰應用

panyanyany發表於2019-02-21

目前系統的 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
複製程式碼

相關文章