# MySQL 中的分庫分表
## <blockquote class="danger"><p>分庫和分表解決了什么問題?</p></blockquote>
### 把以前存在一個數據庫實例里的數據拆分成多個數據庫實例,部署在不同的服務器中,這是分庫。
### 分庫是為了解決服務器資源受單機限制,頂不住高并發訪問的問題,把請求分配到多臺服務器上,降低服務器壓力。
### 把以前存在一張表里面的數據拆分成多張表,這是分表。
### 分表是為了解決由于單張表數據量多大,而導致查詢慢的問題。
## <blockquote class="danger"><p>一般怎么分庫?</p></blockquote>
### 一般分庫都是按照業務劃分的,比如訂單庫、用戶庫。
## <blockquote class="danger"><p>分庫會帶來哪些問題?</p></blockquote>
1. 事務問題
關系型數據庫,有很大一點在于它保證事務完整性,分庫之后單機事務就用不上了,必須使用分布式事務來解決。
1. 連表JOIN 查詢問題
在一個庫中的時候我們還可以利用 JOIN 來連表查詢,而跨庫了之后就無法使用 JOIN 了。
## 解決辦法:
1. 就是在業務代碼中進行關聯,也就是先把一個表的數據查出來,然后通過得到的結果再去查另一張表,然后利用代碼來關聯得到最終的結果。
2. 適當的冗余一些字段,避免JOIN操作
## <blockquote class="danger"><p>一般怎么分表</p></blockquote>
1. 垂直分表

垂直分表的原理比較簡單,一般就是把某幾列拆成一個新表,這樣單行數據就會變小,B+樹里的單個數據頁(固定16kb)內能放入的行數就會變多,從而使單表能放入更多的數據。這樣內存存放更多有用的數據,就減少了磁盤的訪問次數,性能就得到提升。
2. 水平分表

分表算法可以分為:Hash 路由,范圍路由,路由表
* Hash 路由
其實就是選擇表中的某一列,然后進行 Hash 運算,將 Hash 運算得到的結果再對子表數進行取模,這樣就能均勻的將數據分到不同的子表上。
* 優點是:
數據分布均勻
* 缺點是:
就是增加子表的時候麻煩,得重新映射數據
* 范圍路由
其實很簡單,可以是時間,也可以是地址,表示一定的范圍的即可。
比如本來一張 User 表,我可以分 User\_HZ、User\_BJ、User\_SH,按照地名來劃分 User。
比如 log 表,我可以將表分為 log\_202103、 log\_202104,把日志按照年月來劃分。
* 路由表
是專門搞個表來記錄路由信息,一般不怎么用。
## <blockquote class="danger"><p>分表會帶來哪些問題?</p></blockquote>
垂直分表還好,就是查詢數據需要關聯一下。
水平分表會帶來很多問題:
* 排序、count、分頁問題
如果一個用戶的數據被拆分到多個表中,那查詢結果分頁就不像以前單張表那樣直接就能查出來了,像 count 操作也是一樣的。
* 全局主鍵的問題
以前單表的時候很簡單,就是主鍵自增,現在分表了之后就有點尷尬了,所以需要一些手段來保證全局主鍵唯一。
1. 還是自增,只不過自增步長設置一下。比如現在有三張表,步長設置為3,三張表 ID 初始值分別是1、2、3。 這樣第一張表的 ID 增長是 1、4、7。第二張表是2、5、8。第三張表是3、6、9,這樣就不會重復了。
2. UUID,這種最簡單,但是不連續的主鍵插入會導致嚴重的頁分裂,性能比較差。
3. 分布式 ID,比較出名的就是 Twitter 開源的 sonwflake 雪花算法。