
为什么千万级MySQL必须分库分表?
单表数据量突破千万级后,性能断崖式下跌是必然现象。索引层级超过4层时B+树检索效率明显下降,高频写入会导致页分裂加剧。某电商平台曾实测:订单表达到1200万条时,即使有索引,高峰期查询延迟仍从50ms飙升至800ms。
分库分表的核心技术选型
水平拆分 vs 垂直拆分
水平拆分是把同一张表的数据按行分散到不同库表,适合单表数据膨胀场景。垂直拆分则是按列分离,将不常用字段或大字段独立存储:
拆分方式 | 适用场景 | 改造复杂度 |
---|---|---|
水平拆分 | 订单/日志等海量表 | 高 |
垂直拆分 | 包含TEXT/BLOB字段 | 中 |
分片策略的生死抉择
某社交平台采用双分片键方案:用户维度用哈希分片,时间维度用范围分片,成功将QPS峰值从15万提升到42万。
源码改造的五个关键步骤
连接池层的魔改
原生JDBC连接池需要重写分片路由逻辑。通过继承AbstractRoutingDataSource实现动态数据源切换,注意要重写以下方法:
protected Object determineCurrentLookupKey() {
return ShardingContext.getShardKey();
}
SQL解析器的深度定制
利用Druid的SQLParser模块改造SQL重写逻辑,特别是处理跨库JOIN时:
分布式ID生成方案
避免使用数据库自增ID,推荐三种方案:
踩坑实录与性能对比
某金融项目在分库分表后出现诡异慢查询,最终定位到是MyBatis批量插入未适配分片规则。改造前后性能对比:
指标 | 改造前 | 改造后 |
---|---|---|
写入TPS | 1200 | 6800 |
平均查询耗时 | 340ms | 89ms |
分布式事务的妥协方案
完全避免分布式事务不现实,实际常用折中方案:
某物流系统采用本地消息表+定时任务扫描,将跨库事务成功率从82%提升到99.6%
跨库JOIN这个老大难问题,其实有几种接地气的解法。最常用的是玩”空间换时间”的把戏——直接把关联字段复制到各个分片表里,比如订单表带着用户姓名跑,虽然多占点存储,但查询时根本不用跨库。有些项目更狠,干脆把整个用户基础信息都冗余到订单表,虽然看着违反三范式,但性能直接起飞。
要是冗余搞不定,那就得拆步骤了。先查维度表拿到ID列表,再拿着这些ID去各个分片表里捞数据,最后在内存里拼结果。某电商平台处理订单-商品关联时就这路子,先用Redis缓存商品信息,查询速度反而比原来单表JOIN还快30%。实在绕不开的复杂查询,上分布式查询引擎也是个选择,不过这种重型武器一般要搭配20-30台节点集群,小项目玩不起。
分库分表后如何解决跨库JOIN查询问题?
通常采用三种方案:1)字段冗余,将关联字段复制到各分片表;2)分两次查询,先查维度表再查事实表;3)使用分布式查询引擎。实际项目中,80%-90%的JOIN可以通过业务 redesign 转化为单表查询。
分库分表后主键ID冲突怎么避免?
必须放弃自增ID,改用分布式ID生成方案。推荐雪花算法(18-20位)或号段模式,两者都能保证全局唯一。某支付系统采用改良版雪花算法,在100-200台机器并发下仍能保持ID单调递增。
单表数据量达到多少才需要考虑分库分表?
通常单表数据量达到800-1200万条时就需要评估拆分。但实际阈值需结合硬件配置和业务特点,高频写入的表可能在500万条就出现性能拐点,而读多写少的表可能撑到2000万条。
分库分表后如何保证数据一致性?
根据业务容忍度选择方案:强一致性场景用XA事务(性能损失40%-60%),最终一致性用TCC或消息队列。某电商订单系统采用本地消息表+定时补偿,将异常订单率控制在0.01%以下。
分库分表后历史数据迁移有哪些注意事项?
采用双写方案过渡3-7天:1)先全量迁移历史数据;2)开启双写;3)校验数据一致性;4)切换读流量。某银行系统迁移2.4亿条数据时,通过分批迁移+CRC32校验将错误率降到百万分之一。