不能直接解决,但能缓解特定场景下的性能压力;分区仅切分物理存储,需配合分区键查询、合理分区策略及索引优化才能生效,否则可能更慢。

分区表能解决单表千万级查询慢的问题吗?
不能直接解决,但能缓解特定场景下的性能压力。分区本身不减少数据量,也不自动建索引,它只是把物理存储切开。如果查询条件没用上分区键(比如 PARTITION BY RANGE (created_at) 却查 WHERE user_id = 123),MySQL 仍要扫描所有分区,甚至比不分区更慢——多了分区定位和合并结果的开销。
必须用对分区键,否则等于白配
分区键必须是主键或唯一键的一部分,且几乎总是要参与 WHERE 条件才能触发分区裁剪(partition pruning)。常见错误是按 id 分区却高频查 status 或 user_id,结果全分区扫描。
- 时间类业务(订单、日志)优先选
created_at或date字段做RANGE分区 - 用户类业务(如分库分表迁移过渡)可考虑
HASH(user_id),但要注意HASH不支持WHERE user_id IN (...)的裁剪,只对等值有效 - 避免用
LIST分区管理动态变化的枚举值(比如状态码),新增状态就得手动ALTER TABLE ... REORGANIZE PARTITION
分区后 DML 操作可能变慢,尤其写入热点集中
MySQL 5.7+ 对分区表的写入优化有限。如果所有新数据都落到最新分区(比如按天分区,每天只写一个分区),该分区的 B+ 树会成为写入瓶颈;而老分区即使空闲也无法分担压力。另外,ALTER TABLE ... ADD PARTITION 是锁表操作,线上慎用。
- 预建未来 3–6 个月的分区(用
ALTER TABLE ... ADD PARTITION),避免每次插入前动态加 - 用
TRUNCATE PARTITION p_old清理历史数据,比DELETE快得多,且不走 undo log -
EXPLAIN PARTITIONS SELECT ...必须检查输出里的partitions列,确认是否只访问目标分区
别忽略二级索引和执行计划的变化
分区表的二级索引默认是“本地索引”(LOCAL),即每个分区独立建一份索引。这意味着 ORDER BY id LIMIT 10 这类查询,MySQL 要在每个匹配分区里各取 10 条,再合并排序——结果集可能远超预期,性能也差。全局索引(GLOBAL)在 MySQL 8.0 才支持,且仅限于唯一索引。
- 非分区键上的
ORDER BY + LIMIT查询,务必加WHERE过滤到单一分区,否则代价陡增 -
SELECT COUNT(*)在分区表上不会走索引优化,而是统计每个分区行数再求和,比单表慢 - 备份时
mysqldump默认不分区导出,大表容易超时;推荐用mysqlpump --set-gtid-purged=OFF或物理备份
EXPLAIN PARTITIONS 输出,或者把分区当成“银弹”忽略了索引和 SQL 写法本身的问题。











