為什麼要分表和分區?
日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過于龐大,導緻資料庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少資料庫的負擔,提高資料庫的效率,通常點來講就是提高表的增删改查效率。
什麼是分表?
分表是将一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們可以稱為子表,每個表都對應三個檔案,myd資料檔案,.myi索引檔案,.frm表結構檔案。這些子表可以分布在同一塊磁盤上,也可以在不同的機器上。app讀寫的時候根據事先定義好的規則得到對應的子表名,然後去操作它。
什麼是分區?
分區和分表相似,都是按照規則分解表。不同在于分表将大表分解為若幹個獨立的實體表,而分區是将資料分段劃分在多個位置存放,可以是同一塊磁盤也可以在不同的機器。分區後,表面上還是一張表,但資料散列到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分區的資料。
mysql分表和分區有什麼聯系呢?
1.都能提高mysql的性高,在高并發狀态下都有一個良好的表現。
2.分表和分區不沖突,可以互相配合的,對于那些大通路量,并且表資料比較多的表,我們可以采取分表和分區結合的方式(如果merge這種分表方式,不能和分區配合的話,可以用其他的分表試),通路量不大,但是表資料很多的表,我們可以采取分區的方式等。
3.分表技術是比較麻煩的,需要手動去建立子表,app服務端讀寫時候需要計算子表名。采用merge好一些,但也要建立子表和配置子表間的union關系。
4.表分區相對于分表,操作友善,不需要建立子表。
我們知道對于大型的網際網路應用,資料庫單表的資料量可能達到千萬甚至上億級别,同時面臨這高并發的壓力。master-slave結構隻能對資料庫的讀能力進行擴充,寫操作還是集中在master中,master并不能無限制的挂接slave庫,如果需要對資料庫的吞吐能力進行進一步的擴充,可以考慮采用分庫分表的政策。
1.分表
在分表之前,首先要選中合适的分表政策(以哪個字典為分表字段,需要将資料分為多少張表),使資料能夠均衡的分布在多張表中,并且不影響正常的查詢。在企業級應用中,往往使用org_id(組織主鍵)做為分表字段,在網際網路應用中往往是userid。在确定分表政策後,當資料進行存儲及查詢時,需要确定到哪張表裡去查找資料,
資料存放的資料表 = 分表字段的内容 % 分表數量
2.分庫
分表能夠解決單表資料量過大帶來的查詢效率下降的問題,但是不能給資料庫的并發通路帶來質的提升,面對高并發的寫通路,當master無法承擔高并發的寫入請求時,不管如何擴充slave伺服器,都沒有意義了。我們通過對資料庫進行拆分,來提高資料庫的寫入能力,即所謂的分庫。分庫采用對關鍵字取模的方式,對資料庫進行路由。
資料存放的資料庫=分庫字段的内容%資料庫的數量
3.即分表又分庫
資料庫分表可以解決單表海量資料的查詢性能問題,分庫可以解決單台資料庫的并發通路壓力問題
當資料庫同時面臨海量資料存儲和高并發通路的時候,需要同時采取分表和分庫政策。一般分表分庫政策如下:
中間變量 = 關鍵字%(資料庫數量*單庫資料表數量)
庫 = 取整(中間變量/單庫資料表數量)
表 = (中間變量%單庫資料表數量)
先談談分表的幾種方式:
1、mysql叢集
事實它并不是分表,但起到了和分表相同的作用。叢集可分擔資料庫的操作次數,将任務分擔到多台資料庫上。叢集可以讀寫分離,減少讀寫壓力。進而提升資料庫性能。
2、自定義規則分表
大表可以按照業務的規則來分解為多個子表。通常為以下幾種類型,也可自己定義規則。
以聊天資訊表為例:
我事先建100個這樣的表,message_00,message_01,message_02……….message_98,message_99.然後根據使用者的id來判斷這個使用者的聊天資訊放到哪張表裡面,你可以用hash的方式來獲得,可以用求餘的方式來獲得,方法很多,各人想各人的吧。下面用hash的方法來獲得表名:
說明一下,上面的這個方法,告訴我們user18991這個使用者的消息都記錄在message_10這張表裡,user34523這個使用者的消息都記錄在message_13這張表裡,讀取的時候,隻要從各自的表中讀取就行了。
優點:避免一張表出現幾百萬條資料,縮短了一條sql的執行時間
缺點:當一種規則确定時,打破這條規則會很麻煩,上面的例子中我用的hash算法是crc32,如果我現在不想用這個算法了,改用md5後,會使同一個使用者的消息被存儲到不同的表中,這樣資料亂套了。擴充性很差。
3,利用merge存儲引擎來實作分表
我覺得這種方法比較适合,那些沒有事先考慮,而已經出現了得,資料查詢慢的情況。這個時候如果要把已有的大資料量表分開比較痛苦,最痛苦的事就是改代碼,因為程式裡面的sql語句已經寫好了,現在一張表要分成幾十張表,甚至上百張表,這樣sql語句是不是要重寫呢?舉個例子,我很喜歡舉例子
mysql>show engines;的時候你會發現mrg_myisam其實就是merge。
從上面的操作中,我不知道你有沒有發現點什麼?假如我有一張使用者表user,有50w條資料,現在要拆成二張表user1和user2,每張表25w條資料,
這樣我就成功的将一張user表,分成了二個表,這個時候有一個問題,代碼中的sql語句怎麼辦,以前是一張表,現在變成二張表了,代碼改動很大,這樣給程式員帶來了很大的工作量,有沒有好的辦法解決這一點呢?辦法是把以前的user表備份一下,然後删除掉,上面的操作中我建立了一個alluser表,隻把這個alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的
a,如果你使用 alter table 來把 merge 表變為其它表類型,到底層表的映射就被丢失了。取而代之的,來自底層 myisam 表的行被複制到已更換的表中,該表随後被指定新類型。
b,網上看到一些說replace不起作用,我試了一下可以起作用的。暈一個先
c,一個 merge 表不能在整個表上維持 unique 限制。當你執行一個 insert,資料進入第一個或者最後一個 myisam 表(取決于 insert_method 選項的值)。mysql 確定唯一鍵值在那個 myisam 表裡保持唯一,但不是跨集合裡所有的表。
d,當你建立一個 merge 表之時,沒有檢查去確定底層表的存在以及有相同的機構。當 merge 表被使用之時,mysql 檢查每個被映射的表的記錄長度是否相等,但這并不十分可靠。如果你從不相似的 myisam 表建立一個 merge 表,你非常有可能撞見奇怪的問題。
c和d在網上看到的,沒有測試,大家試一下吧。
優點:擴充性好,并且程式代碼改動的不是很大
缺點:這種方法的效果比第二種要差一點
三、總結一下
上面提到的三種方法,我實際做過二種,第一種和第二種。第三種沒有做過,是以說的細一點。哈哈。做什麼事都有一個度,超過個度就過變得很差,不能一味的做資料庫伺服器叢集,硬體是要花錢買的,也不要一味的分表,分出來1000表,mysql的存儲歸根到底還以檔案的形勢存在硬碟上面,一張表對應三個檔案,1000個分表就是對應3000個檔案,這樣檢索起來也會變的很慢。我的建議是
方法1和方法2結合的方式來進行分表
方法1和方法3結合的方式來進行分表
我的二個建議适合不同的情況,根據個人情況而定,我覺得會有很多人選擇方法1和方法3結合的方式
日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過于龐大,導緻資料庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少資料庫的負擔,提高資料庫的效率,通常點來講就是提高表的增删改查效率。
mysql分表和分區有什麼聯系呢?