分表是分散数据库压力的好方法。
分表,最直白的意思,就是将一个表结构分为多个表,然后,可以再同一个库里,也可以放到不同的库。
当然,首先要知道什么情况下,才需要分表。个人觉得单表记录条数达到百万到千万级别时就要使用分表了。
分表的分类
**1、纵向分表**
将本来可以在同一个表的内容,人为划分为多个表。(所谓的本来,是指按照关系型数据库的第三范式要求,是应该在同一个表的。)
分表理由:根据数据的活跃度进行分离,(因为不同活跃的数据,处理方式是不同的)
案例:
对于一个博客系统,文章标题,作者,分类,创建时间等,是变化频率慢,查询次数多,而且最好有很好的实时性的数据,我们把它叫做冷数据。而博客的浏览量,回复数等,类似的统计信息,或者别的变化频率比较高的数据,我们把它叫做活跃数据。所以,在进行数据库结构设计的时候,就应该考虑分表,首先是纵向分表的处理。
这样纵向分表后:
首先存储引擎的使用不同,冷数据使用MyIsam 可以有更好的查询数据。活跃数据,可以使用Innodb ,可以有更好的更新速度。
其次,对冷数据进行更多的从库配置,因为更多的操作时查询,这样来加快查询速度。对热数据,可以相对有更多的主库的横向分表处理。
其实,对于一些特殊的活跃数据,也可以考虑使用memcache ,redis之类的缓存,等累计到一定量再去更新数据库。或者mongodb 一类的nosql 数据库,这里只是举例,就先不说这个。
**2、横向分表**
字面意思,就可以看出来,是把大的表结构,横向切割为同样结构的不同表,如,用户信息表,user_1,user_2等。表结构是完全一样,但是,根据某些特定的规则来划分的表,如根据用户ID来取模划分。
分表理由:根据数据量的规模来划分,保证单表的容量不会太大,从而来保证单表的查询等处理能力。
案例:同上面的例子,博客系统。当博客的量达到很大时候,就应该采取横向分割来降低每个单表的压力,来提升性能。例如博客的冷数据表,假如分为100个表,当同时有100万个用户在浏览时,如果是单表的话,会进行100万次请求,而现在分表后,就可能是每个表进行1万个数据的请求(因为,不可能绝对的平均,只是假设),这样压力就降低了很多很多。
延伸:为什么要分表和分区?
日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表。这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕。分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率。
什么是分表?
分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,每个表都对应三个文件,MYD数据文件,.MYI索引文件,.frm表结构文件。这些子表可以分布在同一块磁盘上,也可以在不同的机器上。app读写的时候根据事先定义好的规则得到对应的子表名,然后去操作它。
什么是分区?
分区和分表相似,都是按照规则分解表。不同在于分表将大表分解为若干个独立的实体表,而分区是将数据分段划分在多个位置存放,可以是同一块磁盘也可以在不同的机器。分区后,表面上还是一张表,但数据散列到多个位置了。app读写的时候操作的还是大表名字,db自动去组织分区的数据。
**MySQL分表和分区有什么联系呢?**
1、都能提高mysql的性高,在高并发状态下都有一个良好的表现。
2、分表和分区不矛盾,可以相互配合的,对于那些大访问量,并且表数据比较多的表,我们可以采取分表和分区结合的方式(如果merge这种分表方式,不能和分区配合的话,可以用其他的分表试),访问量不大,但是表数据很多的表,我们可以采取分区的方式等。
3、分表技术是比较麻烦的,需要手动去创建子表,app服务端读写时候需要计算子表名。采用merge好一些,但也要创建子表和配置子表间的union关系。
4、表分区相对于分表,操作方便,不需要创建子表。
我们知道对于大型的互联网应用,数据库单表的数据量可能达到千万甚至上亿级别,同时面临这高并发的压力。Master-Slave结构只能对数据库的读能力进行扩展,写操作还是集中在Master中,Master并不能无限制的挂接Slave库,如果需要对数据库的吞吐能力进行进一步的扩展,可以考虑采用分库分表的策略。
**1、分表**
在分表之前,首先要选中合适的分表策略(以哪个字典为分表字段,需要将数据分为多少张表),使数据能够均衡的分布在多张表中,并且不影响正常的查询。在企业级应用中,往往使用org_id(组织主键)做为分表字段,在互联网应用中往往是userid。在确定分表策略后,当数据进行存储及查询时,需要确定到哪张表里去查找数据,
数据存放的数据表 = 分表字段的内容 % 分表数量
**2、分库**
分表能够解决单表数据量过大带来的查询效率下降的问题,但是不能给数据库的并发访问带来质的提升,面对高并发的写访问,当Master无法承担高并发的写入请求时,不管如何扩展Slave服务器,都没有意义了。我们通过对数据库进行拆分,来提高数据库的写入能力,即所谓的分库。分库采用对关键字取模的方式,对数据库进行路由。
数据存放的数据库=分库字段的内容%数据库的数量
**3、即分表又分库**
数据库分表可以解决单表海量数据的查询性能问题,分库可以解决单台数据库的并发访问压力问题。
当数据库同时面临海量数据存储和高并发访问的时候,需要同时采取分表和分库策略。一般分表分库策略如下:
中间变量 = 关键字%(数据库数量*单库数据表数量)
库 = 取整(中间变量/单库数据表数量)
表 = (中间变量%单库数据表数量)
实例:
1、分库分表
很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表members,查询起来非常之慢,同事的做法是将其散列到100个表中,分别从members0到members99,然后根据mid分发记录到这些表中,牛逼的代码大概是这样子:
复制代码 代码如下:
<?php
for($i=0;$i< 100; $i++ ){
//echo "CREATE TABLE db2.members{$i} LIKE db1.members
";
echo "INSERT INTO members{$i} SELECT * FROM members WHERE mid%100={$i}
";
}
?>
2、不停机修改mysql表结构
同样还是members表,前期设计的表结构不尽合理,随着数据库不断运行,其冗余数据也是增长巨大,同事使用了下面的方法来处理:
先创建一个临时表:
/*创建临时表*/
CREATE TABLE members_tmp LIKE members
然后修改members_tmp的表结构为新结构,接着使用上面那个for循环来导出数据,因为1000万的数据一次性导出是不对的,mid是主键,一个区间一个区间的导,基本是一次导出5万条吧,这里略去了
接着重命名将新表替换上去:
/*这是个颇为经典的语句哈*/
RENAME TABLE members TO members_bak,members_tmp TO members;
就是这样,基本可以做到无损失,无需停机更新表结构,但实际上RENAME期间表是被锁死的,所以选择在线少的时候操作是一个技巧。经过这个操作,使得原先8G多的表,一下子变成了2G多。
⑵ 如何用ACCESS数据库拆分数据
方法一
1、通过Sql语句,然后使用Docmd.runsql 或Currentdb.Execute 执行Sql语句批量拆分
2、通过DAO或ADO 使用Recordset记录集来循环插入,这个需要懂VBA代码及Do while循环
希望可帮到你
⑶ Oracle数据库字段拆分
SELECTREGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,1),
REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,2),
REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,3),
DECODE(REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,5),NULL,NULL,REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,4)),
DECODE(REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,5),NULL,REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,4),REGEXP_SUBSTR(t.PATH_IDS||',','[^,]+',1,5))
FROM机构层级关系表t
前三列根据正则匹配,获取对应的分割后的值,没有啥讲的,
第四列要判断是否存在第五列,如果不存在,则第四列要空,存在则用第四列的值
第五列要判断是否存在第五列,如果不存在,则给第四列的值,存在则用第五列的值
⑷ 数据库关系分解为BCNF范式
标准答案是:AC,BC,CD。
分析如下:R(A,B,C,D)函数依赖于AB^100c,C^D和D^A,找到违反BCNF的依赖项(不需要找到右侧多个属性的度数)并将其分解为BCNF关系的聚合。
关系:C→A,版本C→D,D→A,AB→D,AB→C,AC→D,BC→D,BC→A,BC→D,BD→A,BD→C,CD→A,ABC→D,ABD→C,权值BCD→A。
违反BCNF:C到A,C到D,D到A,AC到D,CD到A。
(4)数据库拆分方案扩展阅读:
BCNF范式在3NF的基础上消除了对主代码子集的依赖。
以仓库管理关系表为例:仓库编号、存储项编号、管理员编号和数量。首先,该表满足第三种标准形式,这意味着管理员只在一个仓库中工作,而一个仓库可以存储多个项目。表中有以下依赖项:
(仓库编号、存储项目编号)——>(管理员编号、数量)
(管理员编号、存储项目编号)——>(仓库编号、数量)
从上面的依赖关系中,我们可以知道(仓库号、存储项号)和(管理员号、存储项号)是表关系中的候选代码。
表中唯一的非键字段是number,它符合第三种范式。但由于存在以下决定关系:
(仓库号)——>(管理员号)
(管理员编号)——>(仓库编号)
也就是说,有一个关键字段来确定关键字段,所以它不符合BCNF。
解决方案:将仓库管理关系表拆分成两个关系仓库管理表(仓库号、管理员号)和仓库表(仓库号、存储项号、数量)使数据库表符合BCNF,消除删除异常、插入异常和更新异常。
⑸ 试说明拆分数据库在数据库管理中的好处
数据库做拆分的几种方式:
按功能划分(垂直
切分
)
将不同功能相关的表放到不同的数据库中,这样做的好处是非常直观。但当某一部分的功能其数据量或性能要求超出了可控的范围,就需要继续对其进行深入的再切分。
⑹ sql数据库表的拆分
参考语句:
select code,
sum(case when play_id=1 then cnt else 0 end ) play_id01,
sum(case when play_id=2 then cnt else 0 end ) play_id02,
sum(case when play_id=3 then cnt else 0 end ) play_id03
form 表
group by code
⑺ 给小白演示 分库分表案例
受群里小伙伴之邀,搞一个分库分表案例,这样让很多没用过分库分表的心里也有个底,不然永远看到的都是网上的各种概念和解决方案性的文章。
由于用户表过于庞大,采取相关SQL优化,还是不能满足,所以现对其进行做分库分表。
数据库: my-sharding
数据库表: t_user
建表语句如下:
关于数据库分库分表通常有两种方案:
下面我们来演示水平拆分,大致思路:
加入有2000万条数据,那么为了方便演示,我们就暂定分为五个库,每个数据库对应五个表。
五个数据库:
每个数据库有五张表:
建表语句如下:
使用技术栈: JDK8 + MySQL + Spring Boot + Mybatis + Shardingsphere + Druid
maven 相关依赖:
配置文件相关配置如下:
分库分表的两个分片类:
下面是业务部分代码,先看 UserMapper.xml 内容:
UserMapper 接口:
为了更好地演示,我这里加入了 controller 层和 service 层,这也是大家平常开发套路。
service 层代码如下:
controller层代码如下:
最后是项目的启动类:
启动项目,启动成功:
下面我们来演示一下新增数据和查询。
先来添加数据到数据库中,这里使用的是IDEA中restful工具:
后台日志:
再查看数据库表中:
到此,我们的数据依旧落库,下面我们来演示一下数据查询。
浏览器里输入:
返回数据:
后台日志:
从日志和返回结果可以看出,已经为我们正确的选择到对应的数据库和表了,这样,一个分库分表的查询就成功了。
本文没有太多的概念,直接使用案例演示。相关概念性的文章,还有分库分表解决方案的文章,网上一堆堆的,感兴趣可以自行查阅。
⑻ oracle数据库按照一定条件把表拆分为多个表
其实不需要拆分表,分区就可以,还是原来的表名,只是将原来的表分成了若干的分区,这样能起到分表的效果,还不用分成很多的表。
比如你原来的表的名字是A,那么将该表改为A1,然后从新建立一个分区表A,分区的依据是班级,也就是list分区,也就是一般意义上的列表分区表。
然后再将A1的数据插入新A表就可以了。
至于分区表的建立方式,往上很多,可以自行查找。
这样操作查询的语句不需要变,只是在不跨分区查询的情况下,相当于分成了若干张表去查询。比如查询1班的成绩,那么就是在1班的分区内,不会有2班的问题,就相当于你用一个指头就能解决问题,不会动用这个手一样。
如果分表的话,那么假设有12个班,那么就要建立12张表,这样的话,语句就要写12次,冗余太大了。
⑼ 浅谈mysql数据库分库分表那些事-亿级数据存储方案
mysql分库分表一般有如下场景
其中1,2相对较容易实现,本文重点讲讲水平拆表和水平拆库,以及基于mybatis插件方式实现水平拆分方案落地。
在 《聊一聊扩展字段设计》 一文中有讲解到基于KV水平存储扩展字段方案,这就是非常典型的可以水平分表的场景。主表和kv表是一对N关系,随着主表数据量增长,KV表最大N倍线性增长。
这里我们以分KV表水平拆分为场景
对于kv扩展字段查询,只会根据id + key 或者 id 为条件的方式查询,所以这里我们可以按照id 分片即可
分512张表(实际场景具体分多少表还得根据字段增加的频次而定)
分表后表名为kv_000 ~ kv_511
id % 512 = 1 .... 分到 kv_001,
id % 512 = 2 .... 分到 kv_002
依次类推!
水平分表相对比较容易,后面会讲到基于mybatis插件实现方案
场景:以下我们基于博客文章表分库场景来分析
目标:
表结构如下(节选部分字段):
按照user_id sharding
假如分1024个库,按照user_id % 1024 hash
user_id % 1024 = 1 分到db_001库
user_id % 1024 = 2 分到db_002库
依次类推
目前是2个节点,假如后期达到瓶颈,我们可以增加至4个节点
最多可以增加只1024个节点,性能线性增长
对于水平分表/分库后,非shardingKey查询首先得考虑到
基于mybatis分库分表,一般常用的一种是基于spring AOP方式, 另外一种基于mybatis插件。其实两种方式思路差不多。
为了比较直观解决这个问题,我分别在Executor 和StatementHandler阶段2个拦截器
实现动态数据源获取接口
测试结果如下
由此可知,我们需要在Executor阶段 切换数据源
对于分库:
原始sql:
目标sql:
其中定义了三个注解
@useMaster 是否强制读主
@shardingBy 分片标识
@DB 定义逻辑表名 库名以及分片策略
1)编写entity
Insert
select
以上顺利实现mysql分库,同样的道理实现同时分库分表也很容易实现。
此插件具体实现方案已开源: https://github.com/bytearch/mybatis-sharding
目录如下:
mysql分库分表,首先得找到瓶颈在哪里(IO or CPU),是分库还是分表,分多少?不能为了分库分表而拆分。
原则上是尽量先垂直拆分 后 水平拆分。
以上基于mybatis插件分库分表是一种实现思路,还有很多不完善的地方,
例如: