1、爲何要分表?java
當一張的數據達到幾百萬時,你查詢一次所花的時間會變多,若是有聯合查詢的話,有可能會死在那兒了。分表的目的就在於此,減少數據庫的負擔,縮短查詢時間。
根據我的經驗,mysql執行一個sql的過程以下:
一、接收到sql;
二、把sql放到排隊隊列中;
三、執行sql;
四、返回執行結果。
在這個執行過程當中最花時間在什麼地方呢?第一,是排隊等待的時間,第二,sql的執行時間。其實這二個是一回事,等待的同時,確定有sql在執行。因此咱們要縮短sql的執行時間。mysql
mysql中有一種機制是表鎖定和行鎖定,爲何要出現這種機制,是爲了保證數據的完整性,我舉個例子來講吧,若是有二個sql都要修改同一張表的同一條數據,這個時候怎麼辦呢,是否是二個sql均可以同時修改這條數據呢?很顯然mysql對這種狀況的處理是,一種是表鎖定(myisam存儲引擎),一個是行鎖定(innodb存儲引擎)。表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定也同樣,別的sql必須等我對這條數據操做完了,才能對這條數據進行操做。若是數據太多,一次執行的時間太長,等待的時間就越長,這也是咱們爲何要分表的緣由。 算法
2、分表方案sql
具體的分表方案有不少,這裏只介紹我使用的方案。車聯網項目裏,車輛軌跡的數據很大,因此將其分爲若干個表,那事先建100個這樣的表,trajectory_00,trajectory_01,trajectory_02……….trajectory_98,trajectory_99.而後根據GPS設備的ID來判斷這個設備的軌跡數據放到哪張表裏面(把設備id和這100張表創建關聯,使得全部設備平均分配到100張表裏,我用的是java裏的hashcode),而後寫個方法根據傳入的設備id得到表名。數據庫
/**
* 根據設備id獲取表名
* @param deviceid
* @return
*/
public static String getTableByDeviceId(String deviceid) {
return "trajectory_"+(Math.abs(deviceid.hashCode())+"").substring(0, 2);
}優化
優勢:避免一張表出現幾百萬條數據,縮短了一條sql的執行時間。
缺點:①當一種規則肯定時,打破這條規則會很麻煩,上面的例子中我用的hash算法是crc32,若是我如今不想用這個算法了,改用md5後,會使同一個設備的數據被存儲到不一樣的表中,這樣數據亂套了。擴展性不好。
②當要同時獲取兩個處在不一樣表裏的設備數據時,要union一下,稍微麻煩點。code
3、總結一下
如今項目運行下來,平均每一個軌跡表trajectory有100W條數據,每張表裏大約有100個設備,如今執行sql查詢體驗良好。其實優先應該考慮的優化方案是建合適的索引,其次纔是分表,或者分庫。索引
作什麼事都有一個度,超過個度就過變得不好,不要一味的分表,分出來1000表,mysql的存儲歸根到底還以文件的形勢存在硬盤上面,一張表對應三個文件,1000個分表就是對應3000個文件,這樣檢索起來也會變的很慢。隊列
其實上面介紹的是水平分表的實施方法,還存在另外一種方法叫作:垂直分表。md5