2025-07-10

分表分庫

當項目比較大的時候,基本上都會進行分表分庫的

後面就講講什麼時候需要分庫,什麼時候需要分表

什麼時候需要分庫

垂直分割

垂直拆分就是要把表按模塊劃分到不同資料庫表中(當然原則還是不破壞第三范式),這種拆分在大型網站的演變過程中是很常見的。當一個網站還在很小的時候,隻有小量的人來開發和維護,各模塊和表都在一起,當網站不斷豐富和壯大的時候,也會變成多個子系統來支撐,這時就有按模塊和功能把表劃分出來的需求。其實,相對於垂直切分更進一步的是服務化改造,說得簡單就是要把原來強耦合的系統拆分成多個弱耦合的服務,通過服務間的調用來滿足業務需求看,因此表拆出來後要通過服務的形式暴露出去,而不是直接調用不同模塊的表,淘寶在架構不斷演變過程,最重要的一環就是服務化改造,把用戶、交易、店鋪、寶貝這些核心的概念抽取成獨立的服務,也非常有利於進行局部的優化和治理,保障核心模塊的穩定性

垂直拆分用於分佈式場景。

當大團隊在做電商項目的時候,基本上都會將一個項目進行拆分,拆分成n個小項目

這樣做的好處就是,基於逆向服務架構,會拆分多個小項目,每個小項目都有自己單獨的資料庫,這樣的話小項目之間互不影響。

這樣叫做垂直分割。

比如:

會員資料庫、訂單資料庫、支付資料庫等等這樣來分

可以減低開發團隊之間的耦合度。就比如,某個團隊把一個資料庫弄掛瞭,對另外的團隊基本沒有影響。假如全部用的一個資料庫,是不是全部都掛瞭,所有用到那個資料庫的團隊項目進度都要延期

什麼時候需要分表

水平分割

上面談到垂直切分隻是把表按模塊劃分到不同資料庫,但沒有解決單表大數據量的問題,而水平切分就是要把一個表按照某種規則把數據劃分到不同表或資料庫裡。例如像計費系統,通過按時間來劃分表就比較合適,因為系統都是處理某一時間段的數據。而像SaaS應用,通過按用戶維度來劃分數據比較合適,因為用戶與用戶之間的隔離的,一般不存在處理多個用戶數據的情況,簡單的按user_id范圍來水平切分

為什麼需要分表,就比如,一個表,幾十年的數據全部在那個表中,查找,無論你加索引還是怎麼,查詢都需要很長的時間。
這個時候就需要做一個分表、分表的規則,一般按照業務需求來定。沒有統一的分法。

比如:

我們的業務場景,主要是存放日志的,日志是需要按照每年存放的

這個時候分表的話,就根據年份來分

再如騰訊的QQ號,根據什麼來分表

如果是根據位數,最大的缺點是分部不均勻!

另外如會員系統,通過手機號登錄。會員表中

可以通過手機號前三位分表(有一些項目是這樣做的,沒多大問題),比如136 138 155等,但是都不是怎麼均勻

最好通過水平分割(取模算法)來分割

假如我們需要把一個表分成3個表,我們可以把一個是數字的字段,比如int主鍵(userid)。

這個時候,我們可以對表中數據的userid字段對3進行取模,然後對於不同的餘數進行分表

這裡的取模字段不能用自動增長的

實現取模算法,我們需要有專門的一張表存放對應的userid字段(用來取模的字段)。

在插入行時,先生成id,然後在該表中取出對應的userid,然後賦值過去

是否需要分表,這個依據項目經驗和實際業務情況來的。一般MySQL單表1000W左右的數據是沒有問題的(前提是應用系統和資料庫等層面設計和優化的比較好)

當然,如果需要分表,肯定是需要提前計劃半年或者一年計劃的。

通俗理解垂直分割和水平分割:水平拆分行,行數據拆分到不同表中, 垂直拆分列,表數據拆分到不同表中

水平分割取模算法案例

使用取模算法分表的最大好處就是,可以非常均勻的分配

首先創建三張表 user0 / user1 /user2 , 然後我再創建 uuid表,該表的作用就是提供自增的id。

創建資料庫: split_horizon

create table user0(
    id int unsigned primary key ,
    name varchar(32) not null default '',
    pwd  varchar(32) not null default ''
)engine=myisam charset utf8;

create table user1(
    id int unsigned primary key ,
    name varchar(32) not null default '',
    pwd  varchar(32) not null default ''
)engine=myisam charset utf8;

create table user2(
    id int unsigned primary key ,
    name varchar(32) not null default '',
    pwd  varchar(32) not null default ''
)engine=myisam charset utf8;


create table uuid(
    id int unsigned primary key auto_increment
)engine=myisam charset utf8;

功能就是 註冊分表,以及進行分表查詢

項目很簡單,看下瞭解下分表是怎麼回事就好,

Service代碼

package com.uifuture.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

/**
 * Created with IntelliJ IDEA.
 * User: 陳浩翔.
 * Date: 2018/2/5.
 * Time: 下午 10:28.
 * Explain:
 */
@Service
public class UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 註冊的代碼
     * @param name
     * @param pwd
     * @return
     */
    public String regit(String name,String pwd){
        //1.生成userid ,-  先獲取到 自定增長ID
        String insertUUidSql = "insert into uuid values(null)";//插入空數據,這裡的id是自動增長的
        jdbcTemplate.update(insertUUidSql);//執行
        Long userid = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);//查詢到最近的添加的主鍵id
        //2.存放具體的那張表中 - 也就是判斷存儲表名稱
        String tableName = "user" + userid % 3;
        //3.插入到具體的表中去- 註冊數據
        String insertUserSql = "INSERT INTO " + tableName + " VALUES ('" + userid + "','" + name + "','" + pwd + "');";
        System.out.println("insertUserSql:" + insertUserSql);
        jdbcTemplate.update(insertUserSql);
        return "success";
    }

    /**
     * 通過userid查詢name
     * @param userid
     * @return
     */
    public String get(Long userid) {
        //具體哪張表
        String tableName = "user" + userid % 3;
        String sql = "select name from " + tableName + " where id="+userid;
        System.out.println("SQL:" + sql);
        return jdbcTemplate.queryForObject(sql, String.class);//執行查詢出name
    }


}

Controller代碼

package com.uifuture.controller;

import com.uifuture.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 * User: 陳浩翔.
 * Date: 2018/2/5.
 * Time: 下午 10:44.
 * Explain:
 */
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 演示註冊的入口
     * @param name
     * @param pwd
     * @return
     */
    @RequestMapping("/regit")
    public String regit(String name, String pwd) {
        return userService.regit(name, pwd);
    }

    /**
     * 演示獲取name
     * @param id
     * @return
     */
    @RequestMapping("/get")
    public String get(Long id) {
        return userService.get(id);
    }

}

分表之後也有些缺點。

1.分頁查詢

2.查詢非常受限制

比如我不查詢那個分表的關鍵字段

所以一般會有主表和次表

主表存放所有的數據。次表根據具體業務需求進行分表

還有mycar中間件具有分表功能,可以學學

取模算法的缺點,如果我們的表發生改變,需要我們重新分,很麻煩

(哈哈,可以使用阿裡雲的rds雲資料庫,這樣就不用我們關心讀寫分離,分表分庫等等。rds是二次開發的資料庫,所以在性能上來說,比其他的關系型資料庫是快很多的。可以自己去瞭解下)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *