分表的目标
我的项目开发中,咱们的数据库数据越来越大,随之而来的是单个表中数据太多。以至于查问数据变慢,而且因为表的锁机制导致利用操作也受到重大影响,呈现了数据库性能瓶颈。
当呈现这种状况时,咱们能够思考分表,行将单个数据库表进行拆分,拆分成多个数据表,而后用户拜访的时候,依据肯定的算法,让用户拜访不同的表,这样数据扩散到多个数据表中,缩小了单个数据表的拜访压力。晋升了数据库拜访性能。
举个栗子
比方咱们最常见的用户表(user 表)
id | user_id | 其余字段 |
---|---|---|
主键 id | 用户 id | 其余字段 |
咱们个别都会用 user_id 去查问对应的用户信息,然而随着业务的增长,这张表会越来越大,甚至上亿,重大影响了查问性能。
所以咱们就会对这张表进行分表处理,分到多张表减小查问压力
分表策略
以分 10 张表为例 (具体分多少张表 依据理论状况来估算)
首先咱们建 10 张表
user1、user2、user3。。。。。user10
个别状况下,咱们都会用作为索引的字段 (user_id) 进行取模解决。想分多少张表,就依照多少取模,比方这个 case 就是 10
$table_name = $user_id % 10;
依照下面的取模公式
- user_id 为 1295 的会落在 user5 外面
- user_id 为 8634 的会落在 user4 外面
- 。。。。。。。
每次 CURD 依据下面查找表的策略进行就行了,这个问题不大,咱们暂且先不多说。
曾经上线的运行中的表怎么办?
其实下面的办法大家应该都晓得怎么用,然而有个问题,曾经上线了的表怎么办?那张表的数据在线上是始终被查找或者扭转的。如何可能进行平滑的分表,并且让用户无感知呢?
办法 1
间接上线,提前写个脚本,脚本内容是把旧表 (user) 的数据同步到 user1 表到 user10 表,一上线了连忙执行
这种办法显著是行不通的,次要是存在以下问题
- 如果执行过程中脚本有问题怎么办?代码全副回滚?
- 脚本把把旧表 (user) 的数据同步到 user1 表到 user10 表,这个脚本得执行多久?如果是 1 个小时,那么这段时间线上和这张表相干的业务都是不失常的
这显然是行不通的,对线上影响很大。
办法 2
先写个同步数据的脚本,脚本内容是把旧表 (user) 的数据同步到 user1 表到 user10 表,脚本同步完了再上线。
这个办法看起来敌对了一些,不过也存在一些问题。
- 脚本同步完,立刻上线,这两件事之间是有一些时间差的,这个时间差中线上表可能有一些改变,这些改变怎么办?
以上两种办法看起来貌似都行不通,所以看来得来点不一样的了。咱们间接看论断。
步骤 1 上线双写
首先咱们把双写上线了,什么意思呢?比方 user_id=123,对于减少,删除,批改操作来说,咱们既操作 user 表,也操作 user_id=123 对应的 user3 表。
function modify($user_id){ // 蕴含减少,删除,批改操作
modify_user(); //modify user 表
$table_name = $user_id % 10;
modify_user($table_name) //modify 对应的分表
}
因为查问的局部还是在 user 表中查问的,所以下面的操作对线上用户是无任何影响的。
步骤 2 全量同步
写一个全量同步 user 表到 user1-user10 的表,最好找个低峰期执行脚本,以防万一影响 user 表的查问
这一步执行之后,因为咱们之前上线了双写(见步骤 1),所以 user 表和 user1-user10 表之间的数据曾经是完全一致的了。
步骤 3 查问新表数据
将查问的局部改到 user1-user10
因为后面两个步骤咱们曾经保障了 user 表和各个分表之间的数据齐全一致性,所以间接把查问的局部改掉是没有任何问题的
如果依照以上步骤执行,那么对线上的数据是没有任何影响的,而且咱们线上就是这么操作了,通过了屡次实际确保不会出问题,放心使用即可。如果这篇文章帮忙到了你,记得点个赞哦。