MySQL分库分表与⽔平分割取模案例
分表分库
当项⽬⽐较⼤的时候,基本上都会进⾏分表分库的
后⾯就讲讲什么时候需要分库,什么时候需要分表
什么时候需要分库
垂直分割
垂直拆分就是要把表按模块划分到不同表中(当然原则还是不破坏第三范式),这种拆分在⼤型⽹站的演变过程中是很常见的。当⼀个⽹站还在很⼩的时候,只有⼩量的⼈来开发和维护,各模块和表都在⼀起,当⽹站不断丰富和壮⼤的时候,也会变成多个⼦来⽀撑,这时就有按模块和功能把表划分出来的需求。其实,相对于垂直切分更进⼀步的是服务化改造,说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务,通过服务间的调⽤来满⾜业务需求看,因此表拆出来后要通过服务的形式暴露出去,⽽不是直接调⽤不同模块的表,淘宝在架构不断演变过程,最重要的⼀环就是服务化改造,把⽤户、交易、店铺、宝贝这些核⼼的概念抽取成独⽴的服务,也⾮常有利于进⾏局部的优化和治理,保障核⼼模块的稳定性
垂直拆分⽤于分布式场景。
当⼤团队在做电商项⽬的时候,基本上都会将⼀个项⽬进⾏拆分,拆分成n个⼩项⽬
这样做的好处就是,基于逆向服务架构,会拆分多个⼩项⽬,每个⼩项⽬都有⾃⼰单独的数据库,这样的话⼩项⽬之间互不影响。
这样叫做垂直分割。
⽐如:
jdbctemplate查询一条数据
会员数据库、订单数据库、⽀付数据库等等这样来分
可以减低开发团队之间的耦合度。就⽐如,某个团队把⼀个数据库弄挂了,对另外的团队基本没有影响。假如全部⽤的⼀个数据库,是不是全部都挂了,所有⽤到那个数据库的团队项⽬进度都要延期
什么时候需要分表
⽔平分割
上⾯谈到垂直切分只是把表按模块划分到不同数据库,但没有解决单表⼤数据量的问题,⽽⽔平切分就是要把⼀个表按照某种规则把数据划分到不同表或数据库⾥。例如像计费系统,通过按时间来划分表就
⽐较合适,因为系统都是处理某⼀时间段的数据。⽽像SaaS应⽤,通过按⽤户维度来划分数据⽐较合适,因为⽤户与⽤户之间的隔离的,⼀般不存在处理多个⽤户数据的情况,简单的按user_id范围来⽔平切分
为什么需要分表,就⽐如,⼀个表,⼏⼗年的数据全部在那个表中,查,⽆论你加索引还是怎么,查询都需要很长的时间。
这个时候就需要做⼀个分表、分表的规则,⼀般按照业务需求来定。没有统⼀的分法。
⽐如:
我们的业务场景,主要是存放⽇志的,⽇志是需要按照每年存放的
这个时候分表的话,就根据年份来分
再如腾讯的QQ号,根据什么来分表
如果是根据位数,最⼤的缺点是分部不均匀!
另外如会员系统,通过⼿机号登录。会员表中
可以通过⼿机号前三位分表(有⼀些项⽬是这样做的,没多⼤问题),⽐如136 138 155等,但是都不是怎么均匀
最好通过⽔平分割(取模算法)来分割
假如我们需要把⼀个表分成3个表,我们可以把⼀个是数字的字段,⽐如int主键(userid)。
这个时候,我们可以对表中数据的userid字段对3进⾏取模,然后对于不同的余数进⾏分表
这⾥的取模字段不能⽤⾃动增长的
实现取模算法,我们需要有专门的⼀张表存放对应的userid字段(⽤来取模的字段)。
在插⼊⾏时,先⽣成id,然后在该表中取出对应的userid,然后赋值过去
是否需要分表,这个依据项⽬经验和实际业务情况来的。⼀般MySQL单表1000W左右的数据是没有问题的(前提是应⽤系统和数据库等层⾯设计和优化的⽐较好)
当然,如果需要分表,肯定是需要提前计划半年或者⼀年计划的。
通俗理解垂直分割和⽔平分割:⽔平拆分⾏,⾏数据拆分到不同表中,垂直拆分列,表数据拆分到不同
表中
⽔平分割取模算法案例
使⽤取模算法分表的最⼤好处就是,可以⾮常均匀的分配
⾸先创建三张表 user0 / user1 /user2 , 然后我再创建 uuid表,该表的作⽤就是提供⾃增的id。
创建数据库: split_horizon
create table user0(
id int unsigned primary key ,
name varchar(32) not null default'',
pwd  varchar(32) not null default''
)engine=myisam charset utf8;
create table user1(
id int unsigned primary key ,
name varchar(32) not null default'',
pwd  varchar(32) not null default''
)engine=myisam charset utf8;
create table user2(
id int unsigned primary key ,
name varchar(32) not null default'',
pwd  varchar(32) not null default''
)engine=myisam charset utf8;
create table uuid(
id int unsigned primary key auto_increment
)
engine=myisam charset utf8;
功能就是注册分表,以及进⾏分表查询
项⽬很简单,看下了解下分表是怎么回事就好,
Service代码
package com.uifuture.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* Created with IntelliJ IDEA.
* User: 陈浩翔.
* Date: 2018/2/5.
* Time: 下午 10:28.
* Explain:
*/
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 注册的代码
* @param name
* @param pwd
* @return
*/
public String regit(String name,String pwd){
//1.⽣成userid ,-  先获取到⾃定增长ID
String insertUUidSql = "insert into uuid values(null)";//插⼊空数据,这⾥的id是⾃动增长的
jdbcTemplate.update(insertUUidSql);//执⾏
Long userid = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);//查询到最近的添加的主键id
//2.存放具体的那张表中 - 也就是判断存储表名称
String tableName = "user" + userid % 3;
//3.插⼊到具体的表中去- 注册数据
String insertUserSql = "INSERT INTO " + tableName + " VALUES ('" + userid + "','" + name + "','" + pwd + "');";        System.out.println("insertUserSql:" + insertUserSql);
jdbcTemplate.update(insertUserSql);
return "success";
}
/**
* 通过userid查询name
* @param userid
* @return
*/
public String get(Long userid) {
//具体哪张表
String tableName = "user" + userid % 3;
String sql = "select name from " + tableName + " where id="+userid;
System.out.println("SQL:" + sql);
return jdbcTemplate.queryForObject(sql, String.class);//执⾏查询出name
}
}
Controller代码
package ller;
import com.uifuture.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created with IntelliJ IDEA.
* User: 陈浩翔.
* Date: 2018/2/5.
* Time: 下午 10:44.
* Explain:
*/
@RestController
public class UserController {
@Autowired
private UserService userService;
/**
* 演⽰注册的⼊⼝
* @param name
* @param pwd
* @return
*/
@RequestMapping("/regit")
public String regit(String name, String pwd) {
it(name, pwd);
}
/
**
* 演⽰获取name
* @param id
* @return
*/
@RequestMapping("/get")
public String get(Long id) {
(id);
}
}
分表之后也有些缺点。
1.分页查询
2.查询⾮常受限制
⽐如我不查询那个分表的关键字段
所以⼀般会有主表和次表
主表存放所有的数据。次表根据具体业务需求进⾏分表
还有mycar中间件具有分表功能,可以学学
取模算法的缺点,如果我们的表发⽣改变,需要我们重新分,很⿇烦
(哈哈,可以使⽤阿⾥云的rds云数据库,这样就不⽤我们关⼼读写分离,分表分库等等。rds是⼆次开发的数据库,所以在性能上来说,⽐其他的关系型数据库是快很多的。可以⾃⼰去了解下)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。