MySQL库表太大怎么办? 数据库分库分表项目实践


Posted in MySQL onApril 11, 2022

一、为什么要分库分表

数据库架构演变

刚开始多数项目用单机数据库就够了,随着服务器流量越来越大,面对的请求也越来越多,我们做了数据库读写分离, 使用多个从库副本(Slave)负责读,使用主库(Master)负责写,master和slave通过主从复制实现数据同步更新,保持数据一致。slave 从库可以水平扩展,所以更多的读请求不成问题

但是当用户量级上升,写请求越来越多,怎么保证数据库的负载足够?增加一个Master是不能解决问题的, 因为数据要保存一致性,写操作需要2个master之间同步,相当于是重复了,而且架构设计更加复杂

这时需要用到分库分表(sharding),把库和表存放在不同的MySQL Server上,每台服务器可以均衡写请求的次数

二、库表太大产生的问题

  • 单库太大:单库处理能力有限、所在服务器上的磁盘空间不足、遇到IO瓶颈,需要把单库切分成更多更小的库
  • 单表太大:CURD效率都很低、数据量太大导致索引文件过大,磁盘IO加载索引花费时间,导致查询超时。所以只用索引还是不行的,需要把单表切分成多个数据集更小的表。MyCat提供的分表算法都在rule.xml,可以根据不同的分表算法进行拆分,比如根据时间拆分、一致性哈希、直接用主键对分表的个数取模等

拆分策略

单个库太大,先考虑是表多还是数据多:

  • 如果因为表多而造成数据过多,则使用垂直拆分,即根据业务拆分成不同的库
  • 如果因为单张表的数据量太大,则使用水平拆分,即把表的数据按照某种规则(rule.xml定义的分表算法)拆分成多张表

分库分表的原则应该是先考虑垂直拆分,再考虑水平拆分

三、垂直拆分

分库分表和读写分离可以共同进行

1. 垂直分库

server.xml

<user name="root">
<property name="password">123456</property>
<property name="schemas">USERDB1,USERDB2</property>
</user>

配置了USERDB1、USERDB2这两个逻辑库

schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
	<!-- 逻辑数据库 -->
	<schema name="USERDB1" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1" /> <!-- 两个逻辑库对应两个不同的数据节点 -->
	<schema name="USERDB2" checkSQLschema="false" sqlMaxLimit="100"dataNode="dn2" />
	<!-- 存储节点 -->
	<dataNode name="dn1" dataHost="node1" database="mytest1" />  <!-- 两个数据节点对应两个不同的物理机器 -->
	<dataNode name="dn2" dataHost="node2" database="mytest2" />  <!-- USERDB1对应mytest1,USERDB2对应mytest2 -->
	<!-- 数据库主机 -->
	<dataHost name="node1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
		<heartbeat>select user()</heartbeat>
		<writeHost host="192.168.131.129" url="192.168.131.129:3306" user="root" password="123456" />
	</dataHost>
	
	<dataHost name="node2" maxCon="1000" minCon="10" balance="0"writeType="0" dbType="mysql" dbDriver="native">
		<heartbeat>select user()</heartbeat>
		<writeHost host="192.168.0.6" url="192.168.0.6:3306" user="root" password="123456" />
	</dataHost>
</mycat:schema>

两个逻辑库对应两个不同的数据节点,两个数据节点对应两个不同的物理机器

MySQL库表太大怎么办? 数据库分库分表项目实践

mytest1和mytest2分成了不同机器上的不同的库,各包含一部分表,它们原来是合在一块的,在一台机器上,现在做了垂直的拆分。
客户端就需要去连接不同的逻辑库了,根据业务操作不同的逻辑库

MySQL库表太大怎么办? 数据库分库分表项目实践

然后配置了两个写库,两台机器把库平分了,分担了原来单机的压力。分库伴随着分表,从业务上对表拆分

2. 垂直分表

垂直分表,基于列字段进行。一般是针对几百列的这种大表,也避免查询时,数据量太大造成的“跨页”问题。

一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到扩展表。访问频率较高的字段单独放在一张表

四、水平分库分表

针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE、HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈,不建议采用

将单张表的数据切分到多个服务器上去,每个服务器具有一部分库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈

分库分表可以和主从复制同时进行,但不基于主从复制;读写分离才基于主从复制

server.xml

<user name="root">
	<property name="password">123456</property>
	<property name="schemas">USERDB</property>
</user>

schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
	<!-- 逻辑数据库 -->
	<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100">
		<table name="user" dataNode="dn1" /> <!-- 这里的user和student都是实际存在的物理表名 -->
		<table name="student" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long"/>
	</schema>
	<!-- 存储节点 -->
	<dataNode name="dn1" dataHost="node1" database="mytest1" />
	<dataNode name="dn2" dataHost="node2" database="mytest2" />
	<!-- 数据库主机 -->
	<dataHost name="node1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
		<heartbeat>select user()</heartbeat>
		<writeHost host="192.168.131.129" url="192.168.131.129:3306" user="root" password="123456" />
	</dataHost>
	<dataHost name="node2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
		<heartbeat>select user()</heartbeat>
		<writeHost host="192.168.0.6" url="192.168.0.6:3306" user="root" password="123456" />
	</dataHost>
</mycat:schema>

MySQL库表太大怎么办? 数据库分库分表项目实践

user表示一个普通的表,直接放在数据节点dn1上,放在一台机器上,这张表不用进行拆分

student表的primaryKey是id,根据id拆分,放在dn1和dn2上,最终这个表要分在两台机器上,在物理上分开了,但是在逻辑上还是一个,往哪张表里增加,在2台机器上查询然后如何合并这些操作都是由mycat完成的

拆分的规则是取模(mod - long),每次插入用id模上存在的机器数(2)

此外还需要在rule.xml中配置以下拆分算法

找到算法mod-long,因为我们将逻辑表student分开映射到两台主机上,所以修改数据节点的数量为2

MySQL库表太大怎么办? 数据库分库分表项目实践

2. 测试水平分表

Linux主机

MySQL库表太大怎么办? 数据库分库分表项目实践

Windows主机

MySQL库表太大怎么办? 数据库分库分表项目实践

登录到mycat的8066端口

MySQL库表太大怎么办? 数据库分库分表项目实践

使用MyCat给user表插入两条数据

MySQL库表太大怎么办? 数据库分库分表项目实践

由于schema.xml配置文件中,逻辑表user只在Linux主机的mytest1库中存在,mycat操作的逻辑表user会影响Linux主机上的物理表,而不会影响Windows主机上的表。我们分别查看一下Linux和Windows主机的user表:

MySQL库表太大怎么办? 数据库分库分表项目实践

MySQL库表太大怎么办? 数据库分库分表项目实践

我们再通过MyCat给student表插入两条数据

MySQL库表太大怎么办? 数据库分库分表项目实践

我们知道schema.xml配置文件中,逻辑表student对应两台主机上的两个库mytest1、mytest2中的两张表,所以对逻辑表插入的两条数据,会实际影响到两张物理表(用id%机器数,决定插入到哪张物理表)。我们分别查看一下Linux和Windows主机的student表:

MySQL库表太大怎么办? 数据库分库分表项目实践

再通过MyCat插入id=3和id=4的数据,应该插入不同主机上的不同物理表

MySQL库表太大怎么办? 数据库分库分表项目实践

MySQL库表太大怎么办? 数据库分库分表项目实践

这就相当于把student表进行水平拆分了

通过MyCat查询的时候只需要正常输入就行,我们配置的是表拆分后放在这2个数据节点上,MyCat会根据配置在两个库上查询并进行数据合并

MySQL库表太大怎么办? 数据库分库分表项目实践

MySQL 相关文章推荐
Mysql 性能监控及调优
Apr 06 MySQL
mysql对于模糊查询like的一些汇总
May 09 MySQL
修改MySQL的默认密码的四种小方法
May 26 MySQL
MySQL对数据表已有表进行分区表的实现
Nov 01 MySQL
排查MySQL生产环境索引没有效果
Apr 11 MySQL
为什么MySQL8新特性会修改自增主键属性
Apr 18 MySQL
解决MySQL报“too many connections“错误
Apr 19 MySQL
MySQL的存储过程和相关函数
Apr 26 MySQL
MySQL数据库实验实现简单数据库应用系统设计
Jun 21 MySQL
MySQL 原理与优化之原数据锁的应用
Aug 14 MySQL
MySQL 原理与优化之Limit 查询优化
Aug 14 MySQL
SQL中去除重复数据的几种方法汇总(窗口函数对数据去重)
May 08 MySQL
排查MySQL生产环境索引没有效果
Apr 11 #MySQL
排查并解决MySQL生产库内存使用率高的报警
Apr 11 #MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
MySQL数据库优化之通过索引解决SQL性能问题
Apr 10 #MySQL
MySQL 外连接语法之 OUTER JOIN
Apr 09 #MySQL
MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
Apr 09 #MySQL
进阶篇之linux环境下安装MySQL数据库
You might like
php使用curl访问https示例分享
2014/01/17 PHP
深入理解PHP 数组之count 函数
2016/06/13 PHP
[原创]php简单防盗链验证实现方法
2016/07/09 PHP
thinkphp修改配置进入默认首页的方法
2017/02/07 PHP
PHP 7.1中AES加解密方法mcrypt_module_open()的替换方案
2017/10/17 PHP
PHP CURL中传递cookie的方法步骤
2019/05/09 PHP
JavaScript中获取元素索引的函数
2010/09/10 Javascript
jQuery 拖动层(在可视区域范围内)
2012/05/24 Javascript
Node.js的特点和应用场景介绍
2014/11/04 Javascript
jQuery实现带玻璃流光质感的手风琴特效
2015/11/20 Javascript
js操作XML文件的实现方法兼容IE与FireFox
2016/06/25 Javascript
如何去除vue项目中的#及其ie9兼容性
2018/01/11 Javascript
Vue.js添加组件操作示例
2018/06/13 Javascript
AngularJs1.x自定义指令独立作用域的函数传入参数方法
2018/10/09 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
2019/06/10 Javascript
JS实现分页导航效果
2020/02/19 Javascript
基于Vue.js+Nuxt开发自定义弹出层组件
2020/10/09 Javascript
python定时采集摄像头图像上传ftp服务器功能实现
2013/12/23 Python
Python时间模块datetime、time、calendar的使用方法
2016/01/13 Python
对Python中的条件判断、循环以及循环的终止方法详解
2019/02/08 Python
Python中将两个或多个list合成一个list的方法小结
2019/05/12 Python
python爬虫豆瓣网的模拟登录实现
2019/08/21 Python
django从后台返回html代码的实例
2020/03/11 Python
英国蛋糕装饰用品一站式商店:Craft Company
2019/03/18 全球购物
澳大利亚儿童鞋在线:The Trybe
2019/07/16 全球购物
技术学校毕业生求职信分享
2013/12/02 职场文书
高中英语教学反思
2014/02/04 职场文书
2015年中秋节主持词
2015/07/30 职场文书
《只有一个地球》教学反思
2016/02/16 职场文书
初中政治教学反思
2016/02/23 职场文书
标准版个人借条怎么写?以及什么是借条?
2019/08/28 职场文书
CSS3 实现NES游戏机的示例代码
2021/04/21 HTML / CSS
MySQL 隔离数据列和前缀索引的使用总结
2021/05/14 MySQL
Python 中random 库的详细使用
2021/06/03 Python
「魔法少女伊莉雅」美游粘土人开订
2022/03/21 日漫
Redis基本数据类型Zset有序集合常用操作
2022/06/01 Redis