- 概念 - 水平分表 - 把一個表的數據分到一個資料庫的多張表中,每個表只有這個表的部分數據 - 核心是把一個大表,分割N個小表,每個表的結構是一樣的,數據不一樣,全部表的數據合起來就是全部數據 - 針對數據量巨大的單張表(比如訂單表),按照某種規則(RANGE,HASH取模等),切分到多張表裡面 ...
-
概念
-
水平分表
-
把一個表的數據分到一個資料庫的多張表中,每個表只有這個表的部分數據
-
核心是把一個大表,分割N個小表,每個表的結構是一樣的,數據不一樣,全部表的數據合起來就是全部數據
-
針對數據量巨大的單張表(比如訂單表),按照某種規則(RANGE,HASH取模等),切分到多張表裡面去
-
但是這些表還是在同一個庫中,所以單資料庫操作還是有IO瓶頸,主要是解決單表數據量過大的問題
-
減少鎖表時間,沒分表前,如果是DDL(create/alter/add等)語句,當需要添加一列的時候mysql會鎖表,期間所有的讀寫操作只能等待
-
-
水平分表的適用場景
- 當一張表的數據達到幾千萬時,查詢一次所花的時間長,需要進行優化,縮短查詢時間
- 微博發送記錄、微信消息記錄、日誌記錄。以id增長或時間劃分
- 網站簽到等活動流水數據。以時間劃分
- 當一張表的數據達到幾千萬時,查詢一次所花的時間長,需要進行優化,縮短查詢時間
-
實戰樣板
-
依賴引入
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency>
-
application
# 數據源 ds0 第一個資料庫 --- 版本:mysql8 shardingsphere: datasource: ds0: connectionTimeoutMilliseconds: 30000 driver-class-name: com.mysql.cj.jdbc.Driver idleTimeoutMilliseconds: 60000 jdbc-url: jdbc:mysql://[ip]:3306/[資料庫]?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true maintenanceIntervalMilliseconds: 30000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 minPoolSize: 50 password: [密碼] type: com.zaxxer.hikari.HikariDataSource username: [用戶名] names: ds0 props: # 列印執行的資料庫以及語句 sql: show: true sharding: tables: [表名]: # 指定表的數據分佈情況,配置數據節點,行表達式標識符使用 ${...} 或 $->{...},但前者與 Spring 本身的文件占位符衝突,所以在 Spring 環境中建議使用 $->{...} actual-data-nodes: ds0.[表名_]$->{0..1} # 水平分表策略+行表達式分片 table-strategy: inline: algorithm-expression: [表名_]$->{[取模欄位] % 2} sharding-column: [取模欄位] #id生成策略 key-generator: column: id props: worker: id: 0 #id生成策略 type: SNOWFLAKE
-
測試
@Test public void testSaveTraffic(){ Random random = new Random(); for(int i=0;i<10;i++){ TrafficDO trafficDO = new TrafficDO(); // 設置取模欄位的值 Int trafficDO.setAccountNo(Long.valueOf(random.nextInt(1000))); trafficMapper.insert(trafficDO); } }
-
結果分析
- 取模欄位accountNo為偶數的對象,存儲到traffic_0表
- 取模欄位accountNo為奇數的對象,存儲到traffic_1表
- 實現水平分表