資料表的水平拆分

2022-02-02 18:50:32 字數 3408 閱讀 9315

一般人們分析問題,總是從問題現象,原因分析,解決方案這樣的思路來分析思考問題,我想對這個資料庫的水平拆分也按這樣的思路來簡單剖析一下。

先從問題現象入手,隨著資料庫表中資料日積月累越來越多,當表記錄數達到千萬甚至億級別時,資料庫表的訪問效率下降明顯,導致外層應用的訪問效率非常差,訪問時間急劇上公升,使用者體驗下降。如果是表資料太大的原因導致訪問速度變慢,一般情況下當訪問與此表相關業務時速度會很慢,而訪問與此表無關的業務時速度會很快。

分析上面的問題現象,明顯的乙個原因是因為某些表的資料記錄太多的原因,導致資料庫訪問效率下降造成的。

既然是某些表資料記錄太多的原因,那我們的解決辦法當然是讓這些表的資料記錄減少到不影響訪問效率為止,同時為了考慮以後這些資料還是會不斷的增長,為了讓這些資料增長後還是可以擴充套件,那需要考慮如何可以將這些資料無限制的水平拆分,而不需要修改上層應用,一般來說只要設計得當,從理論上講水平拆分都是可以無限擴充套件的。

那我們先把記錄數太多的表分成多張表,這時問題來了。

1、對記錄數多的表我們進行拆分,那對與之相關聯的一些錶該怎麼辦?這個問題其實也是現實開發中比較普遍的乙個問題,現在資料庫表一般都會與其他表有關聯的。有人會提出乙個方法就是所有的表都不與其他表關聯,至少在sql執行層面上如此,這樣不就解決了資料或業務關聯問題了啊,但這裡有個問題那就是如果都按照這樣在sql層面完全解耦,而在應用層面再關聯的話,會導致資料庫訪問次數增加很多,而且網路傳輸資料增加,比如a表和b表是關聯表,如果在sql 層面關聯,則只執行乙個sql;如果在sql層面獨立,則需要執行兩個sql,分別查詢出a表資料和b表資料,因為沒有條件關聯過濾,則資料肯定比執行關聯sql多很多,然後再在應用層進行關聯。所以我個人覺得對效能要求高的系統中,還是需要使用sql層面的關聯的,但這裡有乙個原則肯定是要遵守,那就是不能讓多個需要拆分表關聯,因為這會導致拆分標準不一致而導致無法拆分。對關聯sql中的乙個表需要拆分,其他都是相對靜態的無需拆分的表,這種情況下的解決思路是將需拆分表拆分到多個庫中,而靜態表則同步到各個拆分庫中。這裡再上公升一下,分析一下系統的表結構中,一般會分動態表(資料變化很大,資料量也可能很大的表)和靜態表(資料變化很小的表,一般來說都是基礎表,資料量也不會很大),將基礎的靜態表都放到乙個公共庫中,將動態表根據標準分拆到分庫中,拆分完成後基礎資料都在公共庫維護,並同步到分庫中,在分庫中維護動態表,同時在查詢時動態表可以與分庫中靜態表關聯查詢,這樣就解決了這個問題。

2、資料庫表拆分的標準又是什麼,按照什麼來拆分?一般來說這個拆分標準可以按照資料範圍分,比如1-100萬乙個表,100萬-200萬又是乙個表;也可以按照時間順序來拆分,比如一年的資料歸到一張表中等;也可以按照地域範圍來分,比如按照地市來分,每個或多個地市乙個庫等,反正這個個人覺得是按照具體的情況來分的,一般情況下,對帶有較濃的分割標誌的資料庫表,可以根據分割標誌來分割,對沒有較濃分割標誌的資料庫表,則只能按照最笨的方法如資料範圍來拆分了,有時候為了增加拆分質量,還可以先根據乙個分割標誌來分表,在根據另乙個分割標誌來分割槽等複合式的拆分方式來水平拆分資料庫表。

3、資料庫表水平拆分後,訪問資料庫表的sql必須要帶上分割標誌來確定目標資料庫表,如果要對多個拆分資料庫表進行查詢,則需要通過多次訪問資料庫表來完成,同時在應用層面將資料合併來做到。但有時候,一般需要可以通過至少兩種方式(或分割標誌)來獲取目標資料庫表。舉個例子,大型網路遊戲中因為玩家太多了(比如達到幾千萬甚至億級別時),所以將玩家的使用者資訊分庫分表,當使用者登入時,現在一般的做法都是會讓使用者自己選擇是哪一區的,根據這個選擇來確定目標資料庫表,但如果我們改一下,使用者不知道自己是哪一區的,只知道自己的使用者編號,輸入使用者編號後需要由系統自動根據使用者編號來路由到目標資料庫表。在這種情況下,個人覺得需要有乙個規則來保證使用者編號的規律性,比如可以在使用者申請時,針對選擇的不同區來生成不同的使用者編號,比如1區是 aaa+8位的順序編號,2區是bbb+8位的順序編號,這樣的話,對aaa,bbb之類的分類編號是可以通過資料庫表來管理的,比如使用者編號是aaa開頭和abc開頭的都是1區的使用者這樣的規則就可以管理起來,這樣當使用者輸入使用者編號時,系統通過擷取使用者編號前三位,並到資料庫表中查詢出這前三位對應的哪個區,這樣就可以獲得這個使用者的目標資料庫表了。等到查詢出這個使用者資訊後,這個使用者資訊中必定會存在分割標誌資訊的(這個例子中就是屬於哪個區的),對這個使用者資訊快取,就不再需要使用之前那種方式來確定目標資料庫表了,而只需要根據快取的使用者資訊中的屬於哪個區的資訊就可以來確定目標資料庫表了。分析這兩種確定目標資料庫表的方式,一般來說前一種方式比較複雜,效能上消耗也較多,這種方式只有在第二種方式無法判斷的情況下使用,所以使用頻率相對來說非常低,而第二種方式則相對簡單,而且效能也很好,這種方式是預設使用方式,使用頻率相對來說非常高,但有時候因為資訊不全無法使用第二種方式,所以必須要有前一種方式來補充使用。

4、資料庫水平拆分成多個庫時,這時有乙個事情是必須會碰到的,那就是資料庫的連線。一般來說,應用伺服器或應用系統對資料庫連線的管理一般會通過連線池來管理,這樣可以大大提高效率,而不會使用動態連線。這裡就出來乙個問題,當乙個資料庫水平拆分成多個資料庫時,必然資料庫連線池也會增加到多個,在一定範圍內應該是不會有問題的,但畢竟應用伺服器的效能也是有上限的,當資料庫水平拆分成n個資料庫時,應用伺服器的效能就會吃不消了,這時候需要對應用伺服器進行擴充套件了,比如一台應用伺服器對應幾個資料庫連線等,當然這是比較深入的事情了,這裡只把問題丟擲來,不再多說。

5、說到這裡要說一下應用設計開發上的問題,首先是對目標資料庫表路由模組必須要獨立,如果路由不獨立出來,那以後萬一路由策略變更的話會死的很慘,而且路由演算法是乙個典型的策略模式應用,最好能實現成策略模式,以方便以後路由策略變更時應用可以無縫的切換路由策略。其次是對開發來說,最好能使用ibatis之類的持久層,既有一定的封裝,也可以將sql獨立配置,這樣在開發人員開發時,可以靈活的寫sql來實現邏輯,也可以對sql語句進行管理,同時dba可以很方便的對這些sql進行專業的優化,而與應用開發無關。現在一些先行者已經在努力實現將資料庫拆分的影響封裝在**中的專案,比如變形蟲專案,這些專案的出現將會使資料庫拆分後對應用開發的影響越來越小。最後乙個是事務,如果可以接受分布式事務的效能那當然是最好的;如果不能接受,那一般的做法就是事務補償(指在同一業務操作中當事務a提交,但事務b發生錯誤回滾後,為保持操作一致性和資料正確性,必須要做事務a操作的反操作來補償事務a的提交,消除事務a的提交對資料結果的影響),但事務補償會增加開發的工作量等問題;或者不是非常重要的業務操作時,通過保證事務b執行的成功率(比如先進行查詢或預執行操作),從而使事務b的失敗率下降到可以忽略的程度,從而可以不考慮事務的問題。

6、還有乙個非常重要的需要說一下,一般來說很多都是對原有系統的改造,這樣的話就必然會有需要對原有資料的處理割接,這塊工作也是非常重要的,資料庫拆分方案做得最好,如果原有資料不能無縫的割接到新的拆分後的資料庫中的話,那都是白搭。另外還有業務層面的問題,比如資料庫表拆分引起的業務流程更改,業務操作習慣更改等方面的問題也要提早考慮和解決。

總之,資料庫表水平拆分是非常複雜的,需要綜合各個方面考慮完善,套用網友cauherk

的說法「

系統的切分是個很複雜的技術活,要綜合考慮,而不僅僅從資料庫層面考慮。

業務的使用、分庫的原則、資料的割接、開發的侵入、可操作的易難程度、後期的管理等等都是需要考慮的因素。

表的垂直拆分和水平拆分

垂直拆分是指資料表列的拆分,把一張列比較多的表拆分為多張表 把不常用的字段單獨放在一張表 把text,blob等大字段拆分出來放在附表中 經常組合查詢的列放在一張表中 垂直拆分更多時候就應該在資料表設計之初就執行的步驟,然後查詢的時候用jion關鍵起來即可 水平拆分是指資料表行的拆分,表的行數超過2...

mysql水平拆分表

比如 將訂單詳情表按照客戶進行拆分 表名 order info 包含字段 orderid order表主鍵 order表有客戶id 將表按照客戶id進行拆分 方法1 create table order info 1 select from select oi.order info from ord...

資料拆分之 垂直拆分 and 水平拆分

對資料進行拆分了。有垂直和水平兩種。垂直拆分比較簡單,也就是本來乙個資料庫,資料量大之後,從業務角度進行拆分多個庫。如下圖,獨立的拆分出訂單庫和使用者庫。水平拆分的概念,是同乙個業務資料量大之後,進行水平拆分。分庫分表方案 分庫分表方案最主要就是路由演算法,把路由的key按照指定的演算法進行路由存放...