MySQL分区表不提升单条点查性能,仅优化批量删旧、范围扫描和减少锁竞争;分区键须含于主键,否则索引失效;仅支持本地索引,跨分区查询性能更差。

分区表不是万能的,先看它解决什么问题
MySQL 分区表本质是把一张大表按规则拆成多个物理子表(ENGINE=InnoDB 下仍是独立 .ibd 文件),但对应用层仍表现为一张表。它**不减少索引大小,也不自动提升单条查询性能**,主要价值在:批量删旧数据(如 DROP PARTITION)、加速范围扫描(如按时间查某几个月)、减少锁竞争(不同分区可并发操作)。如果你的瓶颈是 WHERE user_id = ? 这类点查,分区几乎没用——这时候该优化的是二级索引或主键设计。
选对分区键,否则索引会失效
分区键必须是主键或唯一索引的一部分,否则建表直接报错:ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function。这意味着:如果按 created_at 分区,主键就必须包含 created_at;若想保留 id 为主键,就得改成联合主键 (id, created_at)。后果很实际:原本 WHERE id = 123 走主键索引,加了分区后可能变成全分区扫描,因为 MySQL 无法确定该记录落在哪个分区。
- 推荐场景:按时间字段(
DATE/DATETIME)做RANGE或LIST分区,且业务查询天然带时间范围(如WHERE created_at BETWEEN '2024-01-01' AND '2024-06-30') - 避免场景:按
user_id % 100做HASH分区,同时又高频查WHERE order_no = ?——除非order_no也在分区表达式里,否则每个分区都得查一遍 - 注意
TO_DAYS()和YEAR()的兼容性:前者支持到 2100 年左右,后者在跨年边界容易出错(比如YEAR('2024-12-31')和YEAR('2025-01-01')不同,但分区边界若设为VALUES LESS THAN (2025),会导致 2025 年 1 月数据进错区)
分区表上的索引,到底是本地还是全局
MySQL 只支持 本地索引(LOCAL),即每个分区维护自己的 B+ 树。没有真正的全局索引。这意味着:跨分区查询(如 WHERE status = 'paid')必然触发所有分区的索引查找,再合并结果。性能不会比不分区好,甚至更差(多了一层分区路由开销)。所以:
- 别指望靠分区表 + 普通二级索引解决高并发点查问题
- 如果必须按非分区字段查,优先考虑覆盖索引(
INDEX(status, created_at, amount)),让索引本身包含所需字段,避免回表 -
PRIMARY KEY必须含分区键 → 实际上强制你把时间维度“嵌入”主键,这会影响插入顺序和页分裂,尤其当created_at非单调时(如补录历史数据)
执行计划里看到 partition 字段,不代表就高效
用 EXPLAIN PARTITIONS 看执行计划时,partitions 列显示实际访问的分区名(如 p202401,p202402),这只是说明 MySQL 成功剪枝了无关分区。但关键要看 type 和 key:如果 type 是 ALL 或 index,说明这个分区内部仍在全扫;如果 key 是 NULL,说明连本地索引都没用上。常见陷阱:
Magento是一套专业开源的PHP电子商务系统。Magento设计得非常灵活,具有模块化架构体系和丰富的功能。易于与第三方应用系统无缝集成。Magento开源网店系统的特点主要分以下几大类,网站管理促销和工具国际化支持SEO搜索引擎优化结账方式运输快递支付方式客户服务用户帐户目录管理目录浏览产品展示分析和报表Magento 1.6 主要包含以下新特性:•持久性购物 - 为不同的
EXPLAIN PARTITIONS SELECT * FROM orders WHERE created_at > '2024-03-01' AND status = 'shipped';
即使只访问 p202403,p202404 两个分区,若 status 上无索引,每个分区仍要全表扫描。正确做法是建复合索引:INDEX(created_at, status)(注意顺序:分区键在前,才能被用于分区剪枝 + 索引下推)。
真正容易被忽略的是分区维护成本:新增分区要 ALTER TABLE ... REORGANIZE PARTITION,大表可能锁表数分钟;DROP PARTITION 虽快,但会触发一次完整的事务日志刷盘,高峰期可能拖慢写入。这些操作没法在线平滑完成。









