從字面上簡單理解,就是把本來存儲於一個庫的數據分塊存儲到多個庫上,把本來存儲於一個表的數據分塊存儲到多個表上。 mysql
當一張表的數據達到幾千萬時,你查詢一次所花的時間會變多,若是有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在於此,減少數據庫的負擔,縮短查詢時間。 sql
mysql中有一種機制是表鎖定和行鎖定,是爲了保證數據的完整性。表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定也同樣,別的sql必須等我對這條數據操做完了,才能對這條數據進行操做。 數據庫
將表按照功能模塊、關係密切程度劃分出來,部署到不一樣的庫上。例如,咱們會創建定義數據庫workDB、商品數據庫payDB、用戶數據庫userDB、日誌數據庫logDB等,分別用於存儲項目數據定義表、商品定義表、用戶數據表、日誌數據表等。 編程
當一個表中的數據量過大時,咱們能夠把該表的數據按照某種規則,例如userID散列,進行劃分,而後存儲到多個結構相同的表,和不一樣的庫上。例如,咱們的userDB中的用戶數據表中,每個表的數據量都很大,就能夠把userDB切分爲結構相同的多個userDB:part0DB、part1DB等,再將userDB上的用戶數據表userTable,切分爲不少userTable:userTable0、userTable1等,而後將這些表按照必定的規則存儲到多個userDB上。 緩存
應該使用哪種方式來實施數據庫分庫分表,這要看數據庫中數據量的瓶頸所在,並綜合項目的業務類型進行考慮。 服務器
若是數據庫是由於表太多而形成海量數據,而且項目的各項業務邏輯劃分清晰、低耦合,那麼規則簡單明瞭、容易實施的垂直切分必是首選。而若是數據庫中的表並很少,但單表的數據量很大、或數據熱度很高,這種狀況之下就應該選擇水平切分,水平切分比垂直切分要複雜一些,它將本來邏輯上屬於一體的數據進行了物理分割,除了在分割時要對分割的粒度作好評估,考慮數據平均和負載平均,後期也將對項目人員及應用程序產生額外的數據管理負擔。 架構
在現實項目中,每每是這兩種狀況兼而有之,這就須要作出權衡,甚至既須要垂直切分,又須要水平切分。咱們的遊戲項目便綜合使用了垂直與水平切分,咱們首先對數據庫進行垂直切分,而後,再針對一部分表,一般是用戶數據表,進行水平切分。 分佈式
好比對於某網站平臺的數據庫表-公司表,數據量很大,這種能預估出來的大數據量表,咱們就事先分出個N個表,這個N是多少,根據實際狀況而定。某網站如今的數據量至可能是5000萬條,能夠設計每張表容納的數據量是500萬條,也就是拆分紅10張表,那麼如何判斷某張表的數據是否容量已滿呢?能夠在程序段對於要新增數據的表,在插入前先作統計表記錄數量的操做,當<500萬條數據,就直接插入,當已經到達閥值,能夠在程序段新建立數據庫表(或者已經事先建立好),再執行插入操做。 性能
若是要把已有的大數據量表分開比較痛苦,最痛苦的事就是改代碼,由於程序裏面的sql語句已經寫好了。用merge存儲引擎來實現分表, 這種方法比較適合. 大數據
在執行分庫分表以後,因爲數據存儲到了不一樣的庫上,數據庫事務管理出現了困難。若是依賴數據庫自己的分佈式事務管理功能去執行事務,將付出高昂的性能代價;若是由應用程序去協助控制,造成程序邏輯上的事務,又會形成編程方面的負擔。
在執行了分庫分表以後,難以免會將本來邏輯關聯性很強的數據劃分到不一樣的表、不一樣的庫上,這時,表的關聯操做將受到限制,咱們沒法join位於不一樣分庫的表,也沒法join分表粒度不一樣的表,結果本來一次查詢可以完成的業務,可能須要屢次查詢才能完成。
額外的數據管理負擔,最顯而易見的就是數據的定位問題和數據的增刪改查的重複執行問題,這些均可以經過應用程序解決,但必然引發額外的邏輯運算,例如,對於一個記錄用戶成績的用戶數據表userTable,業務要求查出成績最好的100位,在進行分表以前,只需一個order by語句就能夠搞定,可是在進行分表以後,將須要n個order by語句,分別查出每個分表的前100名用戶數據,而後再對這些數據進行合併計算,才能得出結果。
MySQL的主從複製解決了數據庫的讀寫分離,並很好的提高了讀的性能,其圖以下:
其主從複製的過程以下圖所示:
可是,主從複製也帶來其餘一系列性能瓶頸問題:
那問題產生總得解決的,這就產生下面的優化方案,一塊兒來看看。
若是把業務切割得足夠獨立,那把不一樣業務的數據放到不一樣的數據庫服務器將是一個不錯的方案,並且萬一其中一個業務崩潰了也不會影響其餘業務的正常進行,而且也起到了負載分流的做用,大大提高了數據庫的吞吐能力。通過垂直分區後的數據庫架構圖以下:
然而,儘管業務之間已經足夠獨立了,可是有些業務之間或多或少總會有點聯繫,如用戶,基本上都會和每一個業務相關聯,何況這種分區方式,也不能解決單張表數據量暴漲的問題,所以爲什麼不試試水平分割呢?
這是一個很是好的思路,將用戶按必定規則(按id哈希)分組,並把該組用戶的數據存儲到一個數據庫分片中,即一個sharding,這樣隨着用戶數量的增長,只要簡單地配置一臺服務器便可,原理圖以下:
如何來肯定某個用戶所在的shard呢,能夠建一張用戶和shard對應的數據表,每次請求先從這張表找用戶的shard id,再從對應shard中查詢相關數據,以下圖所示: