三、mycat分库分表

第五章 分库分表
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业
务将表进行分类,分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同
的库上面,如下图:
在这里插入图片描述
系统被切分成了,用户,订单交易,支付几个模块。

5.1 如何分库
一个问题:在两台主机上的两个数据库中的表,能否关联查询?
答案:不可以关联查询。
分库的原则:有紧密关联关系的表应该在一个库里,相互没有关联关系的表可以分到
不同的库里。

#客户表 rows:20CREATE TABLE customer(
id INT AUTO_INCREMENT,
NAME VARCHAR(200),
PRIMARY KEY(id)
);
#订单表 rows:600CREATE TABLE orders(
id INT AUTO_INCREMENT,
order_type INT,
customer_id INT,
amount DECIMAL(10,2),
PRIMARY KEY(id)
);
#订单详细表 rows:600CREATE TABLE orders_detail(
id INT AUTO_INCREMENT,
detail VARCHAR(2000),
order_id INT,
PRIMARY KEY(id)
);
#订单状态字典表 rows:20
CREATE TABLE dict_order_type(
id INT AUTO_INCREMENT,
order_type VARCHAR(200),
PRIMARY KEY(id)
);

以上四个表如何分库?客户表分在一个数据库,另外三张都需要关联查询,分在另外
一个数据库。

5.2 如何分表
1、选择要拆分的表
MySQL 单表存储数据条数是有瓶颈的,单表达到 1000 万条数据就达到了瓶颈,会
影响查询效率,需要进行水平拆分(分表)进行优化。
例如:例子中的 orders、orders_detail 都已经达到 600 万行数据,需要进行分表
优化。
2、分表字段
以 orders 表为例,可以根据不同自字段进行分表
编号 分表字段 效果
1 id(主键、或创建时间) 查询订单注重时效,历史订单被查询的次数
少,如此分片会造成一个节点访问多,一个
访问少,不平均。
2 customer_id(客户 id) 根据客户 id 去分,两个节点访问平均,一
个客户的所有订单都在同一个节点
5.3 实现分库分表
Mycat2 一大优势就是可以在终端直接创建数据源、集群、库表,并在创建时指定
分库、分表。与 1.6 版本比大大简化了分库分表的操作

1、添加数据库、存储数据源
/*+ mycat:createDataSource{
"name":"dw0",
"url":"jdbc:mysql://192.168.140.100:3306",
"user":"root",
"password":"123123"
} */;
/*+ mycat:createDataSource{
"name":"dr0",
"url":"jdbc:mysql://192.168.140.100:3306",
"user":"root",
"password":"123123"
} */;
/*+ mycat:createDataSource{
"name":"dw1",
"url":"jdbc:mysql://192.168.140.99:3306",
"user":"root",
"password":"123123"
} */;
/*+ mycat:createDataSource{
"name":"dr1",
"url":"jdbc:mysql://192.168.140.99:3306",
"user":"root",
"password":"123123"
} */;
#通过注释命名添加数据源后,在对应目录会生成相关配置文件
cd /usr/local/mycat/conf/datasources
#如下图

在这里插入图片描述
2、添加集群配置
把新添加的数据源配置成集群

#//在 mycat 终端输入
/*!
mycat:createCluster{"name":"c0","masters":["dw0"],"replicas":["dr0"]}
*/;
/*!
mycat:createCluster{"name":"c1","masters":["dw1"],"replicas":["dr1"]}
*/;
#可以查看集群配置信息
cd /usr/local/mycat/conf/clusters
#如下图

在这里插入图片描述
3、创建全局表

#添加数据库db1
CREATE DATABASE db1;
#在建表语句中加上关键字 BROADCAST(广播,即为全局表)
CREATE TABLE db1.`travelrecord` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` varchar(100) DEFAULT NULL,
`traveldate` date DEFAULT NULL,
`fee` decimal(10,0) DEFAULT NULL,
`days` int DEFAULT NULL,
`blob` longblob,
PRIMARY KEY (`id`),
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;
#进入相关目录查看 schema 配置
vim /usr/local/mycat/conf/schemas/db1.schema.json
#可以看到自动生成的全局表配置信息

在这里插入图片描述

4、创建分片表(分库分表)
#在 Mycat 终端直接运行建表语句进行数据分片
CREATE TABLE db1.orders(
id BIGINT NOT NULL AUTO_INCREMENT,
order_type INT,
customer_id INT,
amount DECIMAL(10,2),
PRIMARY KEY(id),
KEY `id` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
dbpartition BY mod_hash(customer_id) tbpartition BY mod_hash(customer_id)
tbpartitions 1 dbpartitions 2;
#数据库分片规则,表分片规则,以及各分多少片
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(1,101,100,100100);
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(2,101,100,100300);
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(3,101,101,120000);
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(4,101,101,103000);
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(5,102,101,100400);
INSERT INTO orders(id,order_type,customer_id,amount)
VALUES(6,102,100,100020);
SELECT * FROM orders;
#同样可以查看生成的配置信息
#进入相关目录查看 schema 配置
vim /usr/local/mycat/conf/schemas/db1.schema.json

在这里插入图片描述
查看数据库可见,分片数据
在这里插入图片描述
在 Mycat 终端查询依然可以看到全部数据
在这里插入图片描述
5、创建 ER 表
与分片表关联的表如何分表,也就是 ER 表如何分表,如下

#在 Mycat 终端直接运行建表语句进行数据分片
CREATE TABLE orders_detail(
`id` BIGINT NOT NULL AUTO_INCREMENT,
detail VARCHAR(2000),
order_id INT,
PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8
dbpartition BY mod_hash(order_id) tbpartition BY mod_hash(order_id)
tbpartitions 1 dbpartitions 2;
INSERT INTO orders_detail(id,detail,order_id) VALUES(1,'detail1',1);
INSERT INTO orders_detail(id,detail,order_id) VALUES(2,'detail1',2);
INSERT INTO orders_detail(id,detail,order_id) VALUES(3,'detail1',3);
INSERT INTO orders_detail(id,detail,order_id) VALUES(4,'detail1',4);
INSERT INTO orders_detail(id,detail,order_id) VALUES(5,'detail1',5);
INSERT INTO orders_detail(id,detail,order_id) VALUES(6,'detail1',6);
*对比数据节点 1

在这里插入图片描述
*对比数据节点 2
在这里插入图片描述

#上述两表具有相同的分片算法,但是分片字段不相同
#Mycat2 在涉及这两个表的 join 分片字段等价关系的时候可以完成 join 的下推
#Mycat2 无需指定 ER,是自动识别的,具体看分片算法的接口
#查看配置的表是否具有 ER 关系,使用
/*+ mycat:showErGroup{}*/

在这里插入图片描述

#group_id 表示相同的组,该组中的表具有相同的存储分布
运行关联查询语句
SELECT * FROM orders o INNER JOIN orders_detail od ON od.order_id=o.id;

在这里插入图片描述
#原理如下
在这里插入图片描述
5.4 常用分片规则
1、分片算法简介
Mycat2 支持常用的(自动)HASH 型分片算法也兼容 1.6 的内置的(cobar)分片算法.
HASH 型分片算法默认要求集群名字以 c 为前缀,数字为后缀,c0 就是分片表第一个
节点,c1 就是第二个节点.该命名规则允许用户手动改变
2、Mycat2 与 1.x 版本区别
Mycat2 Hash 型分片算法多数基于 MOD_HASH(MOD 对应 JAVA 的%运算),实际上是取
余运算。
Mycat2 Hash 型分片算法对于值的处理,总是把分片值转换到列属性的数据类型再
运算。
而 1.x 系列的分片算法统一转换到字符串类型再运算且只能根据一个分片字段计算
出存储节点下标。
Mycat2 Hash 型分片算法适用于等价条件查询。
而 1.x 系列由于含有用户经验的路由规则。1.x 系列的分片规则总是先转换成字符
串再运算。
3、分片规则与适用性
在这里插入图片描述
在这里插入图片描述4、常用分片规则简介
(1)MOD_HASH
[数据分片]HASH 型分片算法-MOD_HASH
如果分片值是字符串则先对字符串进行 hash 转换为数值类型
分库键和分表键是同键:
分表下标=分片值%(分库数量分表数量)
分库下标=分表下标/分表数量
分库键和分表键是不同键:
分表下标= 分片值%分表数量
分库下标= 分片值%分库数量
(2)RIGHT_SHIFT
[数据分片]HASH 型分片算法-RIGHT_SHIFT
RIGHT_SHIFT(字段名,位移数)
仅支持数值类型
分片值右移二进制位数,然后按分片数量取余
HASH 取模哈希 是 是
数值,字符串,如果不是,则转
换成字符串
MM 按月哈希 否 是 DATE,DATETIME
DD 按日期哈希 否 是 DATE,DATETIME
MMDD 按月日哈希 是 是 DATE,DATETIME
WEEK 按周哈希 否 是 DATE,DATETIME
STR_HASH 字符串哈希 是 是 字符串
(3)YYYYMM
[数据分片]HASH 型分片算法-YYYYMM
仅用于分库
(YYYY
12+MM)%分库数.MM 是 1-12
(4)MMDD
仅用于分表
仅 DATE/DATETIME
一年之中第几天%分表数
tbpartitions 不超过 366
5.5 全局序列
Mycat2 在 1.x 版本上简化全局序列,自动默认使用雪花算法生成全局序列号,如
不需要 Mycat 默认的全局序列,可以通过配置关闭自动全局序列
1、建表语句方式关闭全局序列
如果不需要使用 mycat 的自增序列,而使用 mysql 本身的自增主键的功能,需要在
配置中更改对应的建表 sql,不设置 AUTO_INCREMENT 关键字,这样,mycat 就不认为这个
表有自增主键的功能,就不会使用 mycat 的全局序列号.这样,对应的插入 sql 在 mysql
处理,由 mysql 的自增主键功能补全自增值. 雪花算法:引入了时间戳和 ID 保持自增的分布式 ID 生成算法
在这里插入图片描述
建表 sql 可以自动在原型库对应的逻辑表的物理表获取,如果逻辑表的建表 SQL 与
物理表的建表 SQL 不对应,则需要在配置文件中配置建表 SQL. 例如:

#带 AUTO_INCREMENT 关键字使用默认全局序列
CREATE TABLE db1.`travelrecord` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` varchar(100) DEFAULT NULL,
`traveldate` date DEFAULT NULL,
`fee` decimal(10,0) DEFAULT NULL,
`days` int DEFAULT NULL,
`blob` longblob,
PRIMARY KEY (`id`),
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;
#去掉关键字,不使用
CREATE TABLE db1.`travelrecord` (
`id` bigint NOT NULL,
`user_id` varchar(100) DEFAULT NULL,
`traveldate` date DEFAULT NULL,
`fee` decimal(10,0) DEFAULT NULL,
`days` int DEFAULT NULL,
`blob` longblob,
PRIMARY KEY (`id`),
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;

2、设置 Mycat 数据库方式获取全局序列

#1、在prototype服务器的db1库导入dbseq.sql文件
Mycat2已经为用户提供了相关sql脚本,需要在对应数据库下运行脚本,不能通过
Mycat客户端执行。
脚本所在目录mycat/conf

在这里插入图片描述

脚本内容:
DROP TABLE IF EXISTS MYCAT_SEQUENCE;
CREATE TABLE MYCAT_SEQUENCE ( name VARCHAR(64) NOT NULL, current_value
BIGINT(20) NOT NULL, increment INT NOT NULL DEFAULT 1, PRIMARY KEY
(name) ) ENGINE=InnoDB;
-- ----------------------------
-- Function structure for `mycat_seq_currval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_currval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_currval`(seq_name VARCHAR(64)) RETURNS
varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-1,0";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) )
INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval ;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_nextval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(64)) RETURNS
varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE val BIGINT;
DECLARE inc INT;
DECLARE seq_lock INT;
set val = -1;
set inc = 0;
SET seq_lock = -1;
SELECT GET_LOCK(seq_name, 15) into seq_lock;
if seq_lock = 1 then
SELECT current_value + increment, increment INTO val, inc FROM
MYCAT_SEQUENCE WHERE name = seq_name for update;
if val != -1 then
UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name =
seq_name;
end if;
SELECT RELEASE_LOCK(seq_name) into seq_lock;
end if;
SELECT concat(CAST((val - inc + 1) as CHAR),",",CAST(inc as CHAR)) INTO
retval;
RETURN retval;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_setvals`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextvals`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextvals`(seq_name VARCHAR(64), count INT)
RETURNS VARCHAR(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE val BIGINT;
DECLARE seq_lock INT;
SET val = -1;
SET seq_lock = -1;
SELECT GET_LOCK(seq_name, 15) into seq_lock;
if seq_lock = 1 then
SELECT current_value + count INTO val FROM MYCAT_SEQUENCE WHERE
name = seq_name for update;
IF val != -1 THEN
UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name =
seq_name;
END IF;
SELECT RELEASE_LOCK(seq_name) into seq_lock;
end if;
SELECT CONCAT(CAST((val - count + 1) as CHAR), ",", CAST(val as CHAR))
INTO retval;
RETURN retval;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_setval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_setval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_setval`(seq_name VARCHAR(64), value BIGINT)
RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE inc INT;
SET inc = 0;
SELECT increment INTO inc FROM MYCAT_SEQUENCE WHERE name = seq_name;
UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name;
SELECT concat(CAST(value as CHAR),",",CAST(inc as CHAR)) INTO retval;
RETURN retval;
END
;;
DELIMITER ;
INSERT INTO MYCAT_SEQUENCE VALUES ('GLOBAL', 1, 1);
#2、添加全局序列配置文件
进入/mycat/conf/sequences目录,添加配置文件
{数据库名字}_{表名字}.sequence.json
配置内容:
{
"clazz":"io.mycat.plug.sequence.SequenceMySQLGenerator",
"name":"db1_travelrecord",
"targetName": "prototype",
"schemaName":"db1"//指定物理库名
}
可选参数targetName 更改序列号服务器
"targetName": "prototype" 是执行自增序列的节点,也是dbseq.sql导入的节点
dbseq.sql导入的当前库的库名与逻辑表的逻辑库名一致
导入后检查库下有没有mycat_sequence表。
其中increment是序列号自增的步伐,1的时候严格按1递增,1000的时候,mycat会每
次批量递增1000取序列号.此时在多个mycat访问此序列号表的情况下,不能严格自增
NAME列中的值是对应的 库名_表名 该值需要用户设置,即插入一条逻辑表相关的记录, 用于记录序列号
#3、切换为数据库方式全局序列号
使用注释前要导入dbseq.sql以及设置mycat_sequence表内的逻辑表记录
通过注释设置为数据库方式全局序列号
/*+ mycat:setSequence{
"name":"db1_travelrecord",
"clazz":"io.mycat.plug.sequence.SequenceMySQLGenerator",
"name":"db1_travelrecord",
"targetName": "prototype",
"schemaName":"db2"
} */;
#4、切换为雪花算法方式全局序列号
/*+ mycat:setSequence{"name":"db1_travelrecord","time":true} */;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/91472.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFI绕过disable_functions

文章目录 FFI绕过disable_functions[RCTF 2019]NextphpPHP7.4 FFI参考 FFI绕过disable_functions [RCTF 2019]Nextphp 首先来看这道题目 index.php <?php if (isset($_GET[a])) {eval($_GET[a]); } else {show_source(__FILE__); }查看一下phpinfo 发现过滤了很多函数&…

Jmeter(三十一):制造大批量的用户数据数据

需求&#xff1a;因测试需要&#xff0c;要造100w用户数据&#xff0c;通过用户名、手机号、密码可新增用户&#xff0c;其中用户名和电话号码要求100w用户不能重复 要点&#xff1a; 1、通过Bean shell Sampler实现用户名和手机号的足够随机。 符合我们常用规则的手机号&#…

【算法系列篇】位运算

文章目录 前言什么是位运算算法1.判断字符是否唯一1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 丢失的数字2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 两数之和3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 只出现一次的数字4.1 题目要求4.2 做题思路4.3 Java代码实现 5.…

目标检测笔记(十二):如何通过界面化操作YOLOv5完成数据集的自动标注

文章目录 一、意义二、修改源码获取三、自动标注前期准备四、开始自动标注五、可视化标注效果六、XML转换TXT 一、意义 通过界面化操作YOLOv5完成数据集的自动标注的意义在于简化数据标注的流程&#xff0c;提高标注的效率和准确性。 传统的数据集标注通常需要手动绘制边界框…

什么是数字孪生?

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 走进一家汽车装配厂。看到工人将螺母逐渐减少到螺栓上。听到气动工具的嗡嗡声。观看原始的车身沿着生产线滑行&#xff0c;机器人卷起零件。 现在&#xff0c;在线启动其 3D 数字孪生。看到动画数字人类在完全相同但数…

SVN 集中式版本管理平台

1. SVN 命令行工具下载地址 https://www.visualsvn.com/downloads/ 2. 下载SVN 命令行工具后&#xff0c;解压后就可以了&#xff0c;不需要安装的 3. 将bin 文件添加到系统环境变量中&#xff0c;不知道怎么打开系统环境变量的自己问度娘 4. 添加到系统环境变量中&#xff0c;…

TCP/UDP原理

文章目录 一、端口1. 端口的定义和作用2.服务端和客户端的区别3.常见的知名端口号有 二、TCP的原理1.TCP头部封装格式2.TCP可靠性机制三次握手确认机制四次挥手RST结束连接窗口机制 3.完整性校验4.TCP特征5.TCP的适用场景 三、UDP的原理1.UDP头部封装格式2.UDP特征3.UDP的适用场…

递归学习(转载)

转载至 https://www.cnblogs.com/king-lps/p/10748535.html 为避免原文丢失&#xff0c;因此原文转载作者【三年一梦】的帖子 前言 相信不少同学和我一样&#xff0c;在刚学完数据结构后开始刷算法题时&#xff0c;遇到递归的问题总是很头疼&#xff0c;而一看解答&#xff0c…

【C语言】循环语句详解

✨个人主页&#xff1a; Anmia.&#x1f389;所属专栏&#xff1a; C Language &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 目录 1.什么是循环结构&#xff1f; 2.while循环 while流程图 while语句中的break和continue break continue 3.for循环 for流…

谷歌发布Gemini以5倍速击败GPT-4

在Covid疫情爆发之前&#xff0c;谷歌发布了MEENA模型&#xff0c;短时间内成为世界上最好的大型语言模型。谷歌发布的博客和论文非常可爱&#xff0c;因为它特别与OpenAI进行了比较。 相比于现有的最先进生成模型OpenAI GPT-2&#xff0c;MEENA的模型容量增加了1.7倍&#xf…

Chrome小恐龙快跑小游戏——Python实现

目录 视频演示 代码实现 视频演示 Chrome小恐龙快跑小游戏——Python实现 代码实现 import pygame import os import random pygame.init()# Global Constants SCREEN_HEIGHT 600 SCREEN_WIDTH 1100 game_over False SCREEN pygame.display.set_mode((SCREEN_WIDTH, SCR…

【QT】信号和槽(15)

前面的内容说了很多不同的控件如何使用&#xff0c;今天来看下QT的核心&#xff0c;信号与槽&#xff08;Signals and slots&#xff09;&#xff01; 简单理解一下&#xff0c;就是我们的信号与槽连接上了之后&#xff0c;发射一个信号给到槽&#xff0c;槽函数接收到了这个信…