分片前需确认是否真有必要,多数瓶颈源于查询、索引或配置问题;真正需分片的信号是单表超2000万行、主从延迟>5秒、写入QPS超3000且读写分离无效。

分片前先确认:你的数据真需要分片吗?
多数 PHP 应用在单库撑不住之前,瓶颈其实在查询写法、索引缺失或连接池配置上。EXPLAIN 一下慢查询,SHOW PROCESSLIST 看看有没有长事务堵住线程,比一上来就分片更有效。真正需要分片的信号是:单表超 2000 万行、主从延迟持续 > 5 秒、写入 QPS 稳定超过 3000 且无法通过读写分离缓解。
按用户 ID 做哈希分片:简单但要注意取模陷阱
用 md5() 或 sprintf('%u', crc32($uid)) % $shard_count 计算分片号,比直接 $uid % $shard_count 更均匀。但注意:
-
crc32()在 64 位 PHP 中返回有符号整数,负值取模会出错,必须用%u格式化成无符号再算 - 分片数别用质数(如 7、11),优先选 2 的幂(8、16、32),避免取模运算拖慢性能
- 分片键必须是高频查询条件,否则跨分片 JOIN 或
UNION ALL会把性能拉回石器时代
分片后事务怎么保一致性?PHP 层没法强一致
MySQL 自身不支持跨库事务,PHP 用 PDO::beginTransaction() 只能控制单库连接。常见折中方案:
- 写操作拆成“记录日志 + 异步补偿”,比如先写本地分片,再发消息到
redis或kafka触发其他分片更新 - 读场景允许短暂不一致,用
SELECT ... FOR UPDATE锁单分片内数据,避免脏写 - 关键业务(如余额)改用 TCC 模式:Try 阶段预占资源(扣冻结金额)、Confirm 实际扣减、Cancel 解冻,状态存在独立
tcc_transaction表里
分库分表工具选型:别自己造轮子,但得懂它怎么失效
ShardingSphere-Proxy 或 MyCat 能透明路由,但 PHP 代码里仍要避开它们不支持的语法:
本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。
立即学习“PHP免费学习笔记(深入)”;
- 不要用
SELECT * FROM t1 JOIN t2跨分片表(除非分片键相同且能归并) -
GROUP BY和ORDER BY必须带分片键,否则代理层要拉全量数据再聚合 -
INSERT INTO t VALUES (), ()批量插入时,所有值必须落在同一分片,否则报UnsupportedOperationException
分片不是银弹,最麻烦的永远是扩容——加新库后重分数据时,停写窗口、binlog 解析偏移、ID 冲突检测,这些细节比选哈希函数重要得多。










