多数情况下不能,甚至可能更慢;MySQL分区共用LOCK_open全局锁、跨分区查询执行计划差,仅适用于冷热分离明确且查询总命中单一分区的场景。

MySQL 分区表在高并发下是否真能提升性能?
多数情况下不能,甚至可能更慢。分区(PARTITION BY RANGE/LIST/HASH)本质是逻辑拆分、物理文件分散,但 MySQL 5.7/8.0 的分区实现仍共用同一把 LOCK_open 全局锁(尤其在 DML 频繁时),且优化器对跨分区查询的执行计划常不理想。真实高并发场景中,SELECT ... WHERE created_at BETWEEN ? AND ? 这类查询若落在多个分区,反而触发更多元数据扫描和文件句柄切换。
实操建议:
- 仅对「冷热分离」明确、且查询条件总能命中单一分区的场景用分区,比如按月分表的日志表 +
WHERE log_date >= '2024-06-01'能稳定裁剪到 1–2 个分区 - 避免用
HASH分区做高并发写入——哈希冲突会导致热点分区(如用户 ID 哈希后大量落入p3) - 分区数别超过 64;否则
INFORMATION_SCHEMA.PARTITIONS查询本身变慢,影响监控与运维
比分区更有效的高并发优化手段
真正扛住高并发的不是分区,而是减少锁争用与 I/O 放大。重点在引擎层与 SQL 层协同调整。
实操建议:
- 用
InnoDB替代MyISAM,并确认innodb_row_lock_waits和innodb_row_lock_time_avg指标稳定(可通过SHOW ENGINE INNODB STATUS查) - 将高频更新字段单独拆出宽表,避免
UPDATE t SET a=?, b=?, c=?, d=?, e=? WHERE id=?锁整行;改用UPDATE t_counter SET view_count = view_count + 1 WHERE item_id = ? - 批量写入强制走
INSERT INTO ... VALUES (...), (...), (...),禁用单条INSERT;同时调大innodb_log_file_size(建议 ≥ 1G)缓解 redo log 切换瓶颈 - 读多写少场景启用
read_committed隔离级别,降低 gap lock 范围;但注意业务能否容忍不可重复读
分区表必须配合的配置与陷阱
一旦决定用分区,以下配置不调好,等于白设。
实操建议:
-
innodb_file_per_table = ON必须开启,否则所有分区共享ibdata1,删分区不释放磁盘空间 - 建表时显式指定
DATA DIRECTORY和INDEX DIRECTORY将不同分区落到不同 SSD(需 MySQL 8.0.23+ 且文件系统支持) - 禁止在分区键上建前缀索引(如
KEY idx_uid (user_id(8))),会导致分区裁剪失效——优化器无法判断该前缀值属于哪个分区 - 定期用
ALTER TABLE t REORGANIZE PARTITION p_old INTO (PARTITION p_new VALUES LESS THAN (...))合并过期小分区,避免分区数无限增长
替代分区的轻量方案:分表 + 中间件路由
当单表超 2000 万行、QPS > 5000 时,硬分区不如应用层分表清晰可控。
实操建议:
- 用
sharding-jdbc或vitess做透明分片,按user_id % 16路由到t_user_00–t_user_15,比 MySQL 原生分区更易扩容、故障隔离更好 - 分表后主键改用
bigint+ 雪花算法(worker_id区分库),避免自增 ID 冲突 - 跨分表聚合(如统计全站 PV)交由应用层合并,或用
UNION ALL手动拼接(注意ORDER BY/LIMIT必须下推到每个子查询)
SELECT SUM(pv) AS total_pv FROM ( SELECT COUNT(*) AS pv FROM t_access_00 WHERE dt = '2024-06-01' UNION ALL SELECT COUNT(*) AS pv FROM t_access_01 WHERE dt = '2024-06-01' -- ... 其他分表 ) AS u;
分区本身不是银弹,它解决的是数据生命周期管理问题,不是并发吞吐问题。真正卡住高并发的,往往是没关掉 autocommit 导致长事务、没加覆盖索引导致全表扫描、或者误以为 SELECT FOR UPDATE 只锁一行结果却锁了整个索引范围。










