MyCAT分库分表
MyCAT分库分表
前言:
很难评价的软件 尝试通过修改配置文件做到分库分表 你会发现一些很离谱的BUG 或者是主从分离的时候 你也会发现 莫名其妙的BUG
创建基础环境
192.168.3.145 | 192.168.3.159 | 192.168.3.163 |
MyCAT MySQL | MySQL | MySQL |
--更改root密码alter user 'root'@'localhost' identified by '123';--创建远程登录用户
create user 'root'@'%' identified by '123';--给予权限
grant all on *.* to 'root'@'%';
配置MyCAT数据源
mysql -u root -p123456 -h 127.0.0.1 -P8066-- 添加c1数据源
/*+ mycat:createDataSource
{ "name":"dw0","password":"123","url":"jdbc:mysql://192.168.3.159:3306?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF-8", "user":"root",}
*/;-- 添加c2数据源
/*+ mycat:createDataSource
{ "name":"dw1","password":"123","url":"jdbc:mysql://192.168.3.163:3306?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF-8", "user":"root",}
*/;
#PS: 不知道为什么 通过修改配置文件是行不通的 BUG会很多
#PS:保证远程登录用户的存在与密码正确
/*+ mycat:showDataSources{} */\G;
查看数据源/*+ mycat:showDataSources() */;
生成配置文件#vim查看
{"dbType":"mysql","idleTimeout":60000,"initSqls":[],"initSqlsGetConnection":true,"instanceType":"READ","maxCon":1000,"maxConnectTimeout":3000,"maxRetryCount":5,"minCon":1,"name":"c1","password":"123","queryTimeout":0,"type":"JDBC","url":"jdbc:mysql://192.168.3.159:3306?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true","user":"root","weight":0
}
PS :查询
mysql> /*+ mycat:showDataSources{} */\G;
*************************** 1. row ***************************NAME: c2USERNAME: rootPASSWORD: 123MAX_CON: 1000MIN_CON: 1EXIST_CON: 0USE_CON: 0MAX_RETRY_COUNT: 5MAX_CONNECT_TIMEOUT: 3000DB_TYPE: mysqlURL: jdbc:mysql://192.168.3.163:3306?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&autoReconnect=trueWEIGHT: 0INIT_SQL:
INIT_SQL_GET_CONNECTION: trueINSTANCE_TYPE: READIDLE_TIMEOUT: 60000DRIVER: {CreateTime:"2025-08-20 16:05:21",ActiveCount:0,PoolingCount:1,CreateCount:3,DestroyCount:0,CloseCount:5,ConnectCount:7,Connections:[{ID:891191742, ConnectTime:"2025-08-20 16:09:30", UseCount:1, LastActiveTime:"2025-08-20 16:09:30", LastKeepTimeMillis:"2025-08-20 16:14:21"}]
}TYPE: JDBCIS_MYSQL: true
*************************** 2. row ***************************NAME: prototypeDsUSERNAME: rootPASSWORD: 123MAX_CON: 1000MIN_CON: 1EXIST_CON: 0USE_CON: 0MAX_RETRY_COUNT: 5MAX_CONNECT_TIMEOUT: 3000DB_TYPE: mysqlURL: jdbc:mysql://localhost:3306/mysql?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=trueWEIGHT: 0INIT_SQL:
INIT_SQL_GET_CONNECTION: trueINSTANCE_TYPE: READ_WRITEIDLE_TIMEOUT: 60000DRIVER: {CreateTime:"2025-08-20 16:05:21",ActiveCount:0,PoolingCount:2,CreateCount:2,DestroyCount:0,CloseCount:43,ConnectCount:43,Connections:[{ID:1553207331, ConnectTime:"2025-08-20 16:05:23", UseCount:31, LastActiveTime:"2025-08-20 16:06:00", LastKeepTimeMillis:"2025-08-20 16:14:21"},{ID:1199305953, ConnectTime:"2025-08-20 16:05:22", UseCount:12, LastActiveTime:"2025-08-20 16:05:23", LastKeepTimeMillis:"2025-08-20 16:14:21"}]
}TYPE: JDBCIS_MYSQL: true
*************************** 3. row ***************************NAME: c1USERNAME: rootPASSWORD: 123MAX_CON: 1000MIN_CON: 1EXIST_CON: 0USE_CON: 0MAX_RETRY_COUNT: 5MAX_CONNECT_TIMEOUT: 3000DB_TYPE: mysqlURL: jdbc:mysql://192.168.3.159:3306?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&autoReconnect=trueWEIGHT: 0INIT_SQL:
INIT_SQL_GET_CONNECTION: trueINSTANCE_TYPE: READIDLE_TIMEOUT: 60000DRIVER: {CreateTime:"2025-08-20 16:05:21",ActiveCount:0,PoolingCount:1,CreateCount:3,DestroyCount:0,CloseCount:5,ConnectCount:7,Connections:[{ID:1123414141, ConnectTime:"2025-08-20 16:09:30", UseCount:1, LastActiveTime:"2025-08-20 16:09:30", LastKeepTimeMillis:"2025-08-20 16:14:21"}]
}TYPE: JDBCIS_MYSQL: true
3 rows in set (0.01 sec)ERROR:
No query specified--PS:他可能没有配置文件 查询到就好了
配置集群
#/*+ mycat:createCluster{ "name":"c0", "masters":[ "dw0" ], "replicas":[ "dr0" ]} */;
#--name : 自定义名称 唯一性
#--masters:主库 数据源相同
#--replices:从库 数据源相同/*! mycat:createCluster{ "name":"c0", "masters":[ "dw0" ]} */;/*! mycat:createCluster{ "name":"c1", "masters":[ "dw1" ]} */;# 查看集群
/*+ mycat:showClusters{} */;# 查看集群
/*! mycat:showClusters{} */\G;
创建逻辑库
CREATE DATABASE db1 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;vim /usr/local/mycat/conf/schemas/db1.schema.json
## 在里面添加集群的名称,作用是让该集群生成并管理这个库的物理库
"targetName":"prototype"
创建表
use db1;CREATE TABLE `sys_dict` ( `id` bigint NOT NULL AUTO_INCREMENT,`dict_type` int ,`dict_name` varchar(100) DEFAULT NULL,`dict_value` int , PRIMARY KEY (`id`)) ENGINE=InnoDBDEFAULT CHARSET=utf8mb4BROADCAST;
--上面的SQL中有一个BROADCAST 这个就是全局表的标识。INSERT INTO sys_dict(dict_type,dict_name,dict_value) VALUES(1,"男",1);
INSERT INTO sys_dict(dict_type,dict_name,dict_value) VALUES(1,"女",0);# 所有的库中都有的数据select * from sys_dict;
+----+-----------+-----------+------------+
| id | dict_type | dict_name | dict_value |
+----+-----------+-----------+------------+
| 1 | 1 | 男 | 1 |
| 2 | 1 | 女 | 0 |
+----+-----------+-----------+------------+
2 rows in set (0.00 sec)
创建表
这个命令在主库1里创出来的库名叫db1_0 主库2:db1_1 主库1里的表orders_0 主库2: orders_1
相当于主1和主2加起来是完整的,从1和从2是对应主的备份。
CREATE TABLE orders( ID BIGINT NOT NULL AUTO_INCREMENT,ORDER_TYPE INT, CUSTOMER_ID INT,AMOUNT DECIMAL(10,2), PRIMARY KEY(ID)) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 dbpartition BY mod_hash(CUSTOMER_ID) tbpartition By mod_hash(CUSTOMER_ID) tbpartitions 1 dbpartitions 2;# dbpartition BY mod_hash(CUSTOMER_ID): 指定数据库的分片算法及使用哪一条数据进行分片
# tbpartition BY mod_hash(CUSTOMER_ID) :指定表的分片算法及使用哪一条数据进行分片
# tbpartitions 1 表的分片数量
# dbpartitions 2 数据库的分片数量
MyCat 分库分表配置(核心)
以下是 MyCat 扩展的分库分表规则,用于将数据分散存储到多个数据库 / 表中:
-
dbpartition BY mod_hash(CUSTOMER_ID)
- 含义:指定分库规则,使用
mod_hash
(哈希取模)算法,以CUSTOMER_ID
(客户 ID)作为分片键。 - 作用:根据客户 ID 的哈希值对数据库数量取模,决定这条订单数据存储到哪个物理数据库中。
- 含义:指定分库规则,使用
-
dbpartitions 2
- 含义:指定分库数量为 2,即订单数据会被分散到 2 个不同的物理数据库中。
- 配合上一条规则:
CUSTOMER_ID
哈希取模后结果只能是 0 或 1,分别对应第 1 个和第 2 个数据库。
-
tbpartition BY mod_hash(CUSTOMER_ID)
- 含义:指定分表规则,同样使用
mod_hash
算法,以CUSTOMER_ID
作为分片键。 - 作用:在确定了目标数据库后,再根据客户 ID 的哈希值对表数量取模,决定存储到该数据库中的哪个分表。
- 含义:指定分表规则,同样使用
-
tbpartitions 1
- 含义:指定每个数据库中的分表数量为 1。
- 配合上一条规则:由于数量为 1,取模结果只能是 0,因此每个数据库中只会有 1 张
orders
表(不分表,仅分库)。
插入数据
添加数据
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(1,101,100,100101);
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(2,101,100,100101);
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(3,101,100,100101);
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(4,102,101,101102);
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(5,102,101,101102);
INSERT INTO ORDERS(ID,ORDER_TYPE,CUSTOMER_ID,AMOUNT) VALUES(6,102,101,101102);
结果
数据会被分成两部分 存储在不同的库
表配置
定义:ER 表是与主表存在强关联关系(如父子关系)的表,跟随主表的分片规则存储,确保关联数据在同一分库。
特点:
- 依赖主表的分片键(如主表按
user_id
分片,ER 表也按user_id
分片)。 - 主表和 ER 表的数据一定在同一个分库,避免跨库关联。
CREATE TABLE orders_detail( id BIGINT AUTO_INCREMENT,detail VARCHAR(2000),order_id BIGINT, PRIMARY KEY(ID)) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 dbpartition BY mod_hash(order_id) tbpartition By mod_hash(order_id) tbpartitions 1 dbpartitions 2;# dbpartition BY mod_hash(order_id) :指定数据库的分片算法及使用哪一条数据进行分片HASHtbpartition
# BY mod_hash(order_id) :指定表的分片算法及使用哪一条数据进行分片
# HASHtbpartitions 1 表的分片数量
# dbpartitions 2 数据库的分片数量
以下是 MyCat 扩展的分库分表规则,用于将订单详情数据与对应的订单数据存储在同一分片(便于关联查询):
-
dbpartition BY mod_hash(order_id)
- 含义:指定分库规则,使用
mod_hash
(哈希取模)算法,以order_id
(订单 ID)作为分片键。 - 作用:根据订单 ID 的哈希值对数据库数量取模,决定这条详情数据存储到哪个物理数据库中。
- 含义:指定分库规则,使用
-
dbpartitions 2
- 含义:指定分库数量为 2,即详情数据会被分散到 2 个物理数据库中(与
orders
表的分库数量保持一致)。
- 含义:指定分库数量为 2,即详情数据会被分散到 2 个物理数据库中(与
-
tbpartition BY mod_hash(order_id)
- 含义:指定分表规则,使用
mod_hash
算法,以order_id
作为分片键。 - 作用:在确定目标数据库后,根据订单 ID 的哈希值对表数量取模,决定存储到该数据库中的哪个分表。
- 含义:指定分表规则,使用
-
tbpartitions 1
- 含义:指定每个数据库中的分表数量为 1(即每个数据库中只有 1 张
orders_detail
表)。
- 含义:指定每个数据库中的分表数量为 1(即每个数据库中只有 1 张
3. 设计意图与效果
这条配置的核心是让订单详情与对应的订单存储在同一个分片,具体效果:
- 当插入一条订单详情时,MyCat 会根据
order_id
的哈希值计算分片位置(与orders
表中对应订单的分片位置完全一致); - 最终,同一订单的主表数据(
orders
)和详情数据(orders_detail
)会存储在同一个数据库中; - 这种设计能避免跨库关联查询,提高
orders
与orders_detail
表关联查询的效率。
添加数据
添加数据
INSERT INTO orders_detail VALUES(1,"详情1",1);
INSERT INTO orders_detail VALUES(2,"详情2",2);
INSERT INTO orders_detail VALUES(3,"详情3",3);
INSERT INTO orders_detail VALUES(4,"详情4",4);
INSERT INTO orders_detail VALUES(5,"详情5",5);
INSERT INTO orders_detail VALUES(6,"详情6",6);
结果
以单数和双数分表
分库分表参数的核心用法
-
dbpartition BY 算法(分片键)
- 作用:指定分库规则,即 “按什么字段”“用什么算法” 将数据分到不同数据库。
- 你的配置:
dbpartition BY mod_hash(CUSTOMER_ID)
→ 用mod_hash
(哈希取模)算法,以CUSTOMER_ID
(客户 ID)为依据分库。
-
dbpartitions N
- 作用:指定分库的总数量(N 为数字)。
- 你的配置:
dbpartitions 2
→ 数据会被分散到 2 个物理数据库中。
→ 计算逻辑:CUSTOMER_ID
的哈希值 % 2 → 结果 0 或 1,对应 2 个数据库。
-
tbpartition BY 算法(分片键)
- 作用:指定分表规则,即 “按什么字段”“用什么算法” 在单个数据库内分表。
- 你的配置:
tbpartition BY mod_hash(CUSTOMER_ID)
→ 同样用mod_hash
算法,以CUSTOMER_ID
为依据分表。
-
tbpartitions M
- 作用:指定每个数据库内的分表数量(M 为数字)。
- 你的配置:
tbpartitions 1
→ 每个数据库中只创建 1 张表(即不分表,仅分库)。
除了mod_hash(哈希取模),MyCat 还支持多种分片算法,适用于不同业务场景:
范围分片(range
)
-
语法:
dbpartition BY range(分片键)
+dbpartitions N
-
原理:按分片键的数值范围分片(如按 ID 区间、时间范围)。
-
示例:
-- 按订单ID范围分库:ID≤100000存库1,ID>100000存库2 CREATE TABLE orders(...) -- 表结构定义(省略,包含ID等字段) -- 分库规则配置 dbpartition BY range(ID) -- 按ID字段的范围进行分库 dbpartitions 2 -- 分库总数量为2个 -- 具体的范围划分规则 partition by range(ID) (partition p0 values less than (100000), -- 规则1:ID < 100000的记录partition p1 values less than maxvalue -- 规则2:ID ≥ 100000的记录 ); --p0 和 p1 是给 “范围规则” 起的名字,方便 MyCat 识别不同的分片逻辑(比如后续修改、删除某条范围规则时,通过名字定位);可自定义
2. 枚举分片(enum
)
-
语法:
dbpartition BY enum(分片键)
-
原理:按分片键的枚举值指定分片(如按地区、状态)。
-
示例:
sql-- 按订单类型分库:TYPE=101存库1,TYPE=102存库2 CREATE TABLE orders(...) dbpartition BY enum(ORDER_TYPE) --按照分片分库 dbpartitions 2 partition by enum(ORDER_TYPE) (partition p0 values in (101), --ORDER_TYPE=101的为一个库partition p1 values in (102) --ORDER_TYPE=102的为一个库 );
-
适用场景:分片键值是固定枚举(如性别、支付方式)。
3. 时间分片(date
)
-
语法:
dbpartition BY date(分片键, 格式)
-
原理:按时间字段的年 / 月 / 日分片(如按订单创建时间)。
-
示例:
sql-- 按创建时间(CREATE_TIME)的月份分表,每月1张表 CREATE TABLE orders(ID BIGINT NOT NULL AUTO_INCREMENT,ORDER_TYPE INT,CUSTOMER_ID INT,AMOUNT DECIMAL(10,2),CREATE_TIME DATETIME, -- 新增:订单创建时间(分表的依据字段)PRIMARY KEY(ID) ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 -- 分表规则:按CREATE_TIME的"年月"格式分片 tbpartition BY date(CREATE_TIME, 'yyyyMM') -- 分表数量:12张(对应1-12月) tbpartitions 12;
-
适用场景:日志、订单等时间相关数据(便于按时间范围查询)。
-
MyCat 会自动创建 12 张分表,命名格式为
表名_分片索引
,例如:-
orders_0
(存储 1 月数据,对应202301
、202401
等所有 1 月数据) -
orders_1
(存储 2 月数据) - ...
-
orders_11
(存储 12 月数据)
-
4. 一致性哈希分片(consistent_hash
)
-
语法:
dbpartition BY consistent_hash(分片键)
-
原理:基于一致性哈希算法,解决
mod_hash
在分片数量变化时数据迁移量大的问题。 -
示例:
sql-- 按客户ID的一致性哈希分库,减少扩缩容时的数据迁移 CREATE TABLE orders(...) dbpartition BY consistent_hash(CUSTOMER_ID) dbpartitions 3; -- 3个数据库节点
-
适用场景:需要动态扩缩容的集群(如业务增长快,可能增加数据库节点)。
5. 复合分片(多字段组合)
-
语法:
dbpartition BY complex(分片键1, 分片键2)
-
原理:结合多个字段的分片结果,更灵活地分配数据。
-
示例:
sql-- 先按客户ID分库,再按订单类型分表 CREATE TABLE orders(...) dbpartition BY mod_hash(CUSTOMER_ID) dbpartitions 2 tbpartition BY mod_hash(ORDER_TYPE) tbpartitions 3;--举例 --SQL 配置的是 **“先分库、后分表” 的复合分片策略 **,即数据先按CUSTOMER_ID分到不同数据库,再在每个数据库内按ORDER_TYPE分到不同表中 CREATE TABLE book_1 (ID BIGINT NOT NULL, -- 书籍ID(分库依据)name VARCHAR(100) NOT NULL, -- 书籍名称take_count INT NOT NULL, -- 取书数量(分表依据)PRIMARY KEY (ID) ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 -- 第一步:按ID哈希分库(4个库) dbpartition BY mod_hash(ID) dbpartitions 4 -- 第二步:在每个库内按取书数量范围分表 tbpartition BY range(take_count) tbpartitions 3 -- 每个库分3张表 (partition small_take values less than (10), -- 取书数量 <10partition medium_take values less than (50), -- 10≤数量 <50partition large_take values less than maxvalue -- 数量 ≥50 );