«

MySQL分库分表方案,什么时候需要分表

时间:2026-10-5 08:56     作者:emer     分类: 无


前言

做网站的同学肯定都遇到过这种情况:网站用户越来越多,数据库里的表数据量越来越大,查询越来越慢,插入也越来越慢。这时候怎么办?很多同学第一反应就是:分库分表!

但是分库分表不是万能药,也不是说只要数据量大了就一定要分。很多同学上来就分库分表,结果把自己搞的更累了,问题反而更多。

这篇文章就把分库分表的知识点从头到尾讲清楚:什么时候需要分库分表?怎么分?分完之后有什么问题?看完之后你就知道什么时候该分,什么时候不该分了。

一、什么时候需要分库分表

很多同学一上来就问:分库分表好不好?其实这是个伪命题。分库分表是有代价的,不是什么场景都适合。

一般来说,出现下面这些情况的时候,才考虑分库分表:

1. 单表数据量太大

一般来说,MySQL单表数据量到了千万级之后,性能就开始下降了。如果到了亿级,那基本上就必须分了。

但是也不是说千万级就一定要分,要看你的表结构和查询。如果表结构简单,查询也都走索引,几千万条数据性能还是能接受的。

2. 单库压力太大

一个数据库实例能承受的连接数、IOPS、CPU都是有限的。如果单库的QPS太高,扛不住了,这时候就需要分库,把压力分散到多个数据库实例上。

3. 业务发展到一定阶段

很多互联网公司的业务发展到一定阶段,单库单表确实扛不住了,这时候才需要分。创业初期的小项目,根本没必要分库分表,纯属给自己找麻烦。

总结一下: 分库分表是最后的手段,不是第一选择。在分之前,先看看能不能通过优化SQL、加索引、读写分离、加缓存这些手段解决问题。如果这些手段都用了还是不行,再考虑分库分表。

二、分库分表的两种方式

分库分表有两种方式:垂直拆分和水平拆分。

1. 垂直拆分

垂直拆分又分两种:

垂直分库

按照业务把不同的表分到不同的数据库里。比如把用户相关的表放到user库,订单相关的表放到order库,商品相关的表放到product库。

优点:

缺点:

垂直分表

把一张大表的字段拆到两张表里。比如把不常用的字段拆到另一张表里,常用的字段留在原表里。

比如一张用户表,有基本信息和详细信息。把基本信息(id、昵称、头像)放到user表,详细信息(简介、地址、备注)放到user_detail表。

优点:

缺点:

2. 水平拆分

水平拆分就是把同一张表的数据,按照某个规则分到多张表里。每张表的结构是一样的,只是数据不一样。

比如一张user表有1000万条数据,我们把它分成4张表:user_0、user_1、user_2、user_3。按照用户id取模,0的放user_0,1的放user_1,以此类推。

优点:

缺点:

三、怎么选择分片键

水平拆分的时候,最关键的就是选分片键。分片键选不好,后面会很痛苦。

好的分片键有什么特点

  1. 数据分布均匀:不要有的分片数据特别多,有的特别少
  2. 查询都能带上分片键:大部分查询都能根据分片键定位到具体的分片,不用扫全部分片
  3. 尽量不要跨片:尽量避免需要跨片查询的场景

常见的分片键选择

1. 用user_id做分片键

如果你的业务大部分都是跟用户相关的,比如用户的订单、用户的评论,那用user_id做分片键就很合适。同一个用户的数据都在同一个分片上,查询的时候不用跨片。

2. 用order_id做分片键

如果是订单系统,大部分查询都是按订单id查的,那就用order_id做分片键。

3. 按时间做分片

如果是日志类的数据,按时间查询比较多,那就按时间做分片。比如一个月一张表,或者一个季度一张表。

分片算法选什么

常见的分片算法有:

1. 取模

比如:user_id % 4,这样数据会比较均匀。

优点: 数据分布均匀
缺点: 扩容的时候很麻烦,要重新对所有数据做取模,大部分数据都要迁移

2. 范围分片

比如:id在1-1000万的放第一个分片,1000万-2000万的放第二个分片。

优点: 扩容简单,直接加新的分片就行
缺点: 数据分布不均匀,新的数据都写到新的分片上,容易出现热点

3. 一致性哈希

一致性哈希可以解决扩容的时候数据迁移太多的问题。

四、分库分表带来的问题

分库分表不是银弹,分完之后会带来很多新的问题。

1. 分布式事务

原来一个事务里操作同一张表,现在跨了多个分片,原来的本地事务就不管用了,需要用分布式事务。分布式事务的复杂度和性能损耗都是很大的。

2. 跨片查询

原来一条SQL就能查出来的数据,现在要从多个分片查出来再合并。比如要统计所有用户的总数,就得查所有分片然后加起来。如果要分页就更麻烦了。

3. 跨片联表

原来两张表联查很简单,现在两张表在不同的分片上,联查就很麻烦。

4. 全局唯一ID

原来用自增主键就行了,现在分了多个表,自增主键就重复了。需要用全局唯一ID,比如雪花算法。

5. 扩容麻烦

一开始分了4个表,后来数据量太大了,要扩成8个表。这时候数据要重新分布,迁移量很大。

五、常用的分库分表中间件

自己写分库分表的逻辑太麻烦了,一般都是用现成的中间件:

1. ShardingSphere

Apache的开源项目,国内用的比较多。支持分库分表、读写分离、分布式事务这些功能。

2. MyCat

也是一个开源的分库分表中间件,用的也比较多。

3. 官方方案

MySQL本身也有一些分区的功能,比如Range分区、List分区。但是这个是在单库内的分区,不是真正的分库分表。

常见坑

坑1:一上来就分库分表

很多同学刚做项目,就想着分库分表,搞的很复杂。其实小项目根本没必要,单库单表就能扛住。分库分表是等到数据量真的大了再做的事情,不要提前过度设计。

坑2:分片键选的不好

很多同学分片键随便选一个,结果大部分查询都带不上分片键,每次都要扫全部分片,性能反而更差了。分片键一定要选那些查询最常用的字段。

坑3:用取模算法,扩容的时候崩溃了

很多同学一开始用取模算法分了4个表,后来要扩到8个表,结果发现数据全都要重新分布,迁移量巨大,欲哭无泪。所以一开始就要考虑好扩容的问题。

坑4:分完之后跨片查询太多

很多同学分完库分完表之后,发现原来的很多查询都要跨片,性能反而比原来更差了。这就是分片键没选好,或者业务设计的问题。

坑5:以为分库分表是万能的

很多同学觉得分库分表能解决所有性能问题,其实不是。分库分表只是把单表的数据量变小了,但是复杂SQL、慢SQL这些问题还是存在的。优化SQL、加索引这些基础工作还是要做。

总结

MySQL分库分表的核心知识点:

  1. 分库分表是最后的手段,不是第一选择,先试试优化SQL、加索引、读写分离、加缓存
  2. 什么时候需要分:单表千万级以上、单库压力太大、业务真的到那个规模了
  3. 垂直拆分:按业务拆库、按字段拆表
  4. 水平拆分:同一张表按某个规则拆成多张表
  5. 分片键很重要:要数据分布均匀、查询都能带上、尽量不要跨片
  6. 分片算法:取模(均匀但扩容麻烦)、范围(扩容简单但容易有热点)、一致性哈希
  7. 分完之后的问题:分布式事务、跨片查询、跨片联表、全局唯一ID、扩容麻烦
  8. 常用中间件:ShardingSphere、MyCat

记住:分库分表是有代价的,能不分就不分。真的要分的时候,一定要想清楚分片键和分片算法,不然后面会很痛苦。

遇到问题加QQ23979811 协助处理

标签: MySQL 数据库 分库分表 架构 扩容