MySQL單機單表切分實踐

MySQL單機單表切分實踐

  • acmore
  • 2018.10.20

1. 描述

客戶的項目使用MySQL做持久化,MySQL部署在單機服務器上,前期在數據存取上沒有問題。後來加了一個爬蟲項目,爬取百度地圖的數據,數據很快堆到了一億多條,所有的數據都存儲在單個的MySQL數據表中,整體的數據量超過了70GB,查詢時的效率極低,幾分鐘才能出來結果。除此之外,前期分配的磁盤空間不足,整體的數據佔用量也到了95%以上。所以一方面需要遷移MySQL的存儲位置,另一方面需要解決查詢效率的問題。

2. 過程

2.1 存儲遷移

在解決線上問題的時候,我的宗旨一直是儘量別相信中文社區的解決方案(包括本文),不過在做數據遷移的時候圖省事直接找了個CSDN照做了,過程都是淚,最後還是老老實實照着StackOverflow做,遷移MySQL存儲位置的方案看這裏,簡要描述如下:

  1. 假設你的遷移目標目錄是/data/mysql
  2. 假設你的MySQL配置文件的目錄是/etc/mysql/mysql.conf.d/mysqld.conf
1. $ sudo /etc/init.d/mysql stop # 或 sudo service mysql stop
2. $ sudo cp -R -p /var/lib/mysql /data/mysql
3. 打開/etc/mysql/mysql.conf.d/mysqld.conf, 將datadir指向/data/mysql
4. 打開/etc/apparmor.d/usr.sbin.mysqld,將其中所有的/var/lib/mysql修改爲/data/mysql
5. $ sudo /etc/init.d/apparmor reload
6. $ sudo /etc/init.d/mysql restart # 或 sudo service mysql start

按照上述步驟就可以順利完成存儲的遷移,如果期間確實遇到了問題,那麼就刪除存儲目錄下的ib_logfile0ib_logfile1這兩個文件,重新啓動MySQL。

2.2 查詢優化

優化查詢的第一個反應就是加索引,查詢依據主要是一個varchar的列,所以最初考慮直接對這一列加索引,設置了索引之後一直等它運行完成,結果一直做了四個多小時仍然沒有結束。由於這個嘗試早於存儲遷移,而且加索引的過程中會產生大量的臨時文件,所以直接撐爆了磁盤,搞了很久才救回來。也是由於數據量很大的原因,沒有做備份就直接懟了索引,現在想起來也是大膽。這個嘗試之後就加了塊大磁盤,先做好了存儲遷移,然後開始考慮單表切分的問題。

就現在的用戶量而言,主要的壓力並不在服務器本身,所以仍然考慮單機切分。數據表的字段之間沒有特別強的關聯,而且有幾個字段的內容量很大,可是客戶端需要的字段比較多,如果做垂直切分最後還是要Join,因此最後做了表的水平切分。客戶端在查詢的時候總是會帶一個地區參數,而且參數只是城市,可以根據區域做水平切分。如果按照省份做切分,理想狀態下會把數據表均勻切分成30多份,按照目前的數據增長速度,估計幾個月之後又會上升到現在的量級,所以乾脆按照城市進行切分,並且這次直接在新表上加索引。

在準備階段,給數據表一個統一的前綴,結尾加上城市的Canton Id,用代碼批量生成Model類,然後Migrate即可(項目基於Django)。接下來就是切分過程,大致思路是按照id每次從舊錶中撈出10000條數據,根據city字段判斷應該插入的新表,放在臨時列表中,然後批量插入整個臨時列表。在做切分的過程中還是遇到了一點小坑,首先是Django的查詢集緩存問題,規範可以參考官方文檔,做的時候有這個意識,但是還是沒有足夠細心,導致一開始速度慢了很多。另外還有一個更慢的地方,是在拼裝新的Model實例的時候,這個過程理論上應該一瞬間完成,可是卻成了時間瓶頸,檢查了很久發現是一句item.city.canton_id導致了每次都重新查詢一次數據庫,做了City表中id到canton_id的映射之後這個問題才得以解決。外鍵寫起來是個好東西,可是用起來稍不注意就忘了其兇殘的本質,以後儘量不設置外鍵而是自己維護關聯關係,這樣才能時刻記住自己在做什麼

3. 結果

截止目前,遷移工作仍然在進行中,做完之後再來補…


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章