第35期:MySQL 数据垂直拆分
wptr33 2025-01-11 17:49 12 浏览
引言
一般来说讲,提到数据拆分,可以归结为两个层面:一是垂直拆分,二是水平拆分。这里我们来讨论下垂直拆分。
垂直拆分是以数据库、表、列等为单位进行拆分的方法。
正文
MySQL里垂直拆分可以细分为:垂直拆库(实例级别)、垂直拆模(表级别)、垂直拆表(列级别)。
1、垂直拆库:
也即在业务层按照业务逻辑由大拆小,各个子业务之间无关联查询,仅查询单个子业务即可,类似微服务治理的思想。在 MySQL 里表现为将全部表按照业务关联紧密程度拆分后存储在不同的数据库,每个数据库为一台 MySQL 实例,查询仅查对应的数据库实例即可。
如图1所示:
上图展示出原始业务数据的拆分示例,按照不同的业务逻辑分类划分为多个子业务,每个子业务对应一套 MySQL 实例组,每个 MySQL 实例组按照 MySQL 的 HA 架构部署(主从同步、组复制、MySQL CLUSTER等)
图1的优点很明显,原始业务的压力分散到各个小业务上,提升了整体的性能。但也不能忽略缺点:数据库对应用端不透明,应用端必须自己维护路由数据;当单个实例数据量以及请求再次到达上限时,后续拆分非常困难。
2、垂直拆模:
垂直拆模和垂直拆库大体类似,不过垂直拆模的最小单元是 schema ,而不是实例。大家知道,MySQL 的数据库等同于 schema , 一个数据库对应磁盘上的一个文件目录。这种拆分一般是为了解决文件系统中单个目录里文件个数过多导致的性能降低。
如图2所示:
图2显式了比如一个数据库 dbA , 里面含有10000张表,每1000张表单独划分为一个数据库,比如dbA1,dbA2,...,db10;每个数据库的数据无论从物理还是逻辑上都独立的。
举个例子说明下在数据库端垂直拆模的步骤以及对写入和查询请求的影响:
数据库 ytta 下有10000张表,表名分别为t1到t10000.
(debian-ytt1:3500)|(ytta)>select count(*) from information_schema.tables where table_schema='ytta';
+----------+
| count(*) |
+----------+
| 10000 |
+----------+
1 row in set (0.04 sec)
此处把这10000张表平均垂直拆分到数据库 ytt1 到 ytt10 里。
先创建10个数据库 ytt1-ytt10 。
ytt@debian-ytt1:~/mysql-sandboxes/3500/sandboxdata$ for i in `seq 1 10`; \
> do mysql -S mysqld.sock -uroot -proot -e "create database ytt$i";done;
分别往这10个数据库中 COPY 原始数据库的表结构以及数据:
这里采用拷贝表空间的做法(前提是数据库 ytta 下的表都是单表空间,如果非单表空间建议提前转换为单表空间)
对这个10个数据库分别创建对应的表结构;完了删掉初始表空间文件。
root@debian-ytt1:/home/ytt# for i in `seq 0 9`; \
> do for j in `seq 1 1000`; \
> do x=$((j + i * 1000)); \
> mysql -uroot -proot -hdebian-ytt1 -P3500 \
> -e "use ytta;create table ytt$((i+1)).t$x like ytta.t$x;alter table ytt$((i+1)).t$x discard tablespace;"; \
> done; \
> done;
拷贝表空间需要原始表的表空间文件以及.cfg 配置文件。批量 flush 10000张表,导出对应的 .cfg 文件。
SESSION 1:
MySQL Py > conn1 = 'mysql://root:root@debian-ytt1:3500/ytta'
MySQL Py > rs = mysql.get_classic_session(conn1);
MySQL Py > tb_list = []
MySQL Py > for i in range(1,10001):tb_list.append('t' + str(i))
MySQL Py > tb_lists = ','.join(tb_list);
MySQL Py > rs.run_sql('flush tables ' + tb_lists + ' for export');
Query OK, 0 rows affected (46.0182 sec)
检验数据库 ytta 下所有表是否已经生成.cfg文件
root@debian-ytt1:/home/ytt/mysql-sandboxes/3500/sandboxdata/ytta# ls -l t* | wc -l
20000
开始拷贝表空间文件
root@debian-ytt1:/home/ytt/mysql-sandboxes/3500/sandboxdata/ytta# for i in `seq 0 9`; \
> do for j in `seq 1 1000`; \
> do x=$((j + i * 1000)); \
> cp -rfp t$x.cfg t$x.ibd ../ytt$((i + 1))/; \
> done; \
> done;
回到 SESSION 1 来解锁数据库 ytta 下的所有表
MySQL Py > rs.run_sql('unlock tables')
Query OK, 0 rows affected (4.5235 sec)
分别在各个数据库下导入表空间
MySQL Py > for i in range(1,11):
-> for j in range(1,1001):
-> x = j + (i - 1) * 1000
-> rs.run_sql('alter table ytt'+ str(i) +'.t' + str(x) + ' import tablespace')
->
Query OK, 0 rows affected, 0 warning (0.0973 sec)
以上即为在 MySQL 里垂直拆模的大致步骤。
垂直拆模的优点是没有动表结构和数据,只是把表结构和数据隔离到不同的数据库,在逻辑层面上可读性更强,代码改写量非常小。比如原来在数据库 ytta 的 SQL 如下:
select * from t1 join t1001 using(id) join t2001 using(id);
可以更改为:
select * from ytt1.t1 join ytt2.t1001 using(id) join ytt3.t2001 using(id);
跨库写入也一样,直接带入数据库名即可。
3、垂直拆表:
拆分的基本单元是表,而非实例或者数据库模式,将一张表按照字段的被访问频次拆分为不同的表。比如一张表有1000个字段, 按照字段被访问的频次来讲,前100个字段经常被访问,单独划分为一个分表;后面900 个字段不经常访问,划分为另外一个分表。
如图3所示:
上图表A含有5个字段,其中1个主键字段,另外4个非主键字段;按照字段被访问频次不同拆分为两张表A11,A12,两张表拥有同样的主键字段,有点类似我们常说的热表与冷表。
来看看在 MySQL 里实现垂直拆表的简单示例:
建立一张1000个字段的表 t_large(包含主键ID,字段为1001个),并插入1W行记录:
MySQL Py > field_list=[]
MySQL Py > for i in range(1,1001):field_list.append('r' + str(i) + ' int');
MySQL Py > field_lists=','.join(field_list);
MySQL Py > rs.run_sql('create table t_large(id serial primary key,' + field_lists + ')');
Query OK, 0 rows affected (0.6012 sec)
MySQL Py > v_list=[]
MySQL Py > for i in range(1000,2000):v_list.append(str(i));
MySQL Py > v_lists=','.join(v_list)
MySQL Py > for i in range(1,10001):rs.run_sql('insert into t_large select null,'+ v_lists);
Query OK, 1 row affected (0.0109 sec)
Records: 1 Duplicates: 0 Warnings: 0
MySQL Py > rs.run_sql('select count(*) from t_large');
+----------+
| count(*) |
+----------+
| 10000 |
+----------+
1 row in set (0.0671 sec)
按照字段个数,把这表拆成100张小表,每张表字段数为11个(包含主键字段),并且从原表 t_large 里抽取相应的记录。
MySQL Py > for i in range(1,101):
-> f_list1 = []
-> f_list2 = []
-> for j in range(1,11):
-> f_list1.append('r' + str(j + (i-1)*10) + ' int')
-> f_list2.append('r' + str(j + (i-1)*10))
-> rs.run_sql('create table t_large' + str(i) +'( id serial primary key,'+ ','.join(f_list1) + ')')
-> rs.run_sql('insert into t_large' + str(i) +' select id,' + ','.join(f_list2) + ' from t_large')
->
Query OK, 10000 rows affected (1.0415 sec)
Records: 10000 Duplicates: 0 Warnings: 0
假设表 t_large 原先10个字段频繁的被读取,那之后值需要读取表 t_large1 即可,写法上也简洁许多。
原 SQL :
select id,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10 from t_large;
可以替换为:
select * from t_large1;
表更新的性能也有一定提升。原表更新:
MySQL Py > rs.run_sql('update t_large set r1 = ceil(rand()*10000)');
Query OK, 10000 rows affected (8.4471 sec)
Rows matched: 10000 Changed: 10000 Warnings: 0
仅更新字段r1,只需更新对应的拆分表即可。时间上比更新原表要快几十倍。
MySQL Py > rs.run_sql('update t_large1 set r1 = ceil(rand()*10000)');
Query OK, 10000 rows affected (0.5160 sec)
Rows matched: 10000 Changed: 10000 Warnings: 0
总结:
垂直拆分方法基本上分为三类: 垂直拆库(MySQL 里可以叫垂直拆实例)、垂直拆模(MySQL 里的垂直拆库)、垂直拆表。总体来说,垂直拆分的优缺点大致如下:
优点:
- 逻辑上业务更清晰,更容易梳理。
- 对 IO 以及连接数在一定程度上能够得到改善。
缺点:
- 单个分片性能如果到达瓶颈,很难进行更细粒度的切分。
- 拆分很难做到足够彻底,各个分片避免不了低频次的表关联。
关于 MySQL 的技术内容,你们还有什么想知道的吗?赶紧留言告诉小编吧!
相关推荐
- 每天一个AI姬,AMD核显用户有福了,AI绘画打破 NVIDIA 显卡垄断
-
使用StableDiffusion进行AI绘画,并不一定只能使用NVIDIA英伟达显卡,甚至,也不一定只能使用独立显卡。今天我们使用AMD6800H核显,并安装了StableDif...
- NETworkManager:功能强大的网络管理与问题排除工具
-
关于NETworkManagerNETworkManager是一款功能强大的网络管理与问题排除工具,该工具完全开源,可以帮助广大研究人员轻松管理目标网络系统并排除网络疑难问题。该工具使用远程桌面、Po...
- AMD也能深度学习+免费AI绘画:StableDiffusion+ROCm部署教程!
-
某国政客扇扇嘴皮子,CN玩硬件和深度学习的圈子里就掀起了一场风暴,这就是著名的嘴皮子效应(误)。没了高性能计算的A100H100倒也能理解,但是美利坚这波把RTX4090禁售了就让人无语了,所以不少做...
- windows 下编译 python_rtmpstream
-
最近在研究数字人,看了大咖的项目(https://github.com/lipku/metahuman-stream),尝试编译此项目的依赖项目python_rtmpstream(https://gi...
- 如何使用 Python 操作 Git 代码?GitPython 入门介绍
-
花下猫语:今天,我在查阅如何用Python操作Gitlab的时候,看到这篇文章,觉得还不错,特分享给大家。文中还提到了其它几种操作Git的方法,后续有机会的话,再陆续分享之~~作者:匿蟒...
- 网上看了不少,终于把ZlmediaKit流媒体框架搭建起来啦
-
你都站在2023年代了,视频通话、视频直播、视频会议、视频监控就是风口浪尖上的猪师兄,只要你学那么一丁点,拿个高薪的工作不过分吧!我也是半瓶子晃荡的,所以路人呀,共学习,同进步!本篇开始,只讲在Lin...
- MacDown:一款 macOS 的强大 Markdown 编辑器
-
大家好,很高兴又见面了,我是"...
- ZLMediaKit安装配置和推拉流
-
一、ZLMediaKit库简介ZLMediaKit是一个基于...
- 大神赞过的:学习 WebAssembly 汇编语言程序设计
-
文/阿里淘系F(x)Team-旭伦随着前端页面变得越来越复杂,javascript的性能问题一再被诟病。而Javascript设计时就不是为了性能优化设计的,这使得浏览器上可以运行的本地语言一...
- 【Docker】部署WVP视频监控平台
-
回来Docker系列,今天将会跟大家分享一则关于开源WVP视频监控平台的搭建。先说结论吧,一开始按照网上说的一步一步搭建没有搭建成功,不知道是版本太旧还是我这边机器有问题,尝试了好几个不同方式的搭建都...
- MongoDB+GridFS存储文件方案
-
GridFS是MongoDB的一个内置功能,它提供一组文件操作的API以利用MongoDB存储文件,GridFS的基本原理是将文件保存在两个Collection中,一个保存文件索引,一个保存文...
- 【开源】强大、创新且直观的 EDA套件
-
今天分享的LibrePCB是...
- Ollama如何制作自己的大模型?
-
背景Llama3发布了,这次用了...
- Ollama使用指南【超全版】
-
一、Ollama快速入门Ollama是一个用于在本地运行大型语言模型的工具,下面将介绍如何在不同操作系统上安装和使用Ollama。官网:https://ollama.comGithub:http...
- 基于区块链的价值共享互联网即时通讯应用平台源码免费分享
-
——————关注转发之后私信回复【源码】即可免费获取到本项目所有源码基于区块链的价值共享互联网即时通讯应用平台,是一个去中心化的任何人都可以使用的通讯网络,是一款基于区块链的价值共享互联网即时通讯AP...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git 执行pull错误如何撤销 git pull fail
-
面试官:git pull是哪两个指令的组合?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git pull 之后本地代码被覆盖 解决方案
-
git命令之pull git.pull
-
- 最近发表
-
- 每天一个AI姬,AMD核显用户有福了,AI绘画打破 NVIDIA 显卡垄断
- NETworkManager:功能强大的网络管理与问题排除工具
- AMD也能深度学习+免费AI绘画:StableDiffusion+ROCm部署教程!
- windows 下编译 python_rtmpstream
- 如何使用 Python 操作 Git 代码?GitPython 入门介绍
- 网上看了不少,终于把ZlmediaKit流媒体框架搭建起来啦
- MacDown:一款 macOS 的强大 Markdown 编辑器
- ZLMediaKit安装配置和推拉流
- 大神赞过的:学习 WebAssembly 汇编语言程序设计
- 【Docker】部署WVP视频监控平台
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)