MySQL按日期分区表:主键及其他索引查询/更新的执行逻辑咨询
嘿,这个问题问到了分区优化的核心点——毕竟咱们搞分区就是为了少扫数据、快干活嘛!咱们把不同场景拆开来唠清楚:
首先得明确:如果你的自增主键和分区键(日期)没有关联(比如主键就是单独的id INT AUTO_INCREMENT,分区键是created_at DATE),那MySQL查询优化器没法通过自增主键定位到目标分区。
为啥?因为自增主键的值和日期分区键之间没有逻辑映射关系——优化器根本不知道id=1234对应的行存在哪个日期分区里。这种情况下,执行SELECT * FROM your_table WHERE id=1234或者UPDATE your_table SET col=val WHERE id=1234时,优化器会遍历所有分区,逐个检查主键是否匹配。
当然,如果你把主键设计成复合主键,比如PRIMARY KEY(id, created_at)(把分区键包含进去),那情况就不一样了:如果查询条件里同时指定了id和created_at,优化器能直接定位到目标分区;但如果只给id,还是得扫所有分区。
这里先划个MySQL的硬性规则:如果你的表有唯一索引(包括主键),那么分区键必须是所有唯一索引的组成部分——也就是说,你没法创建一个不包含分区键的唯一索引,MySQL会直接报错。
在这个规则下,唯一索引的查询/更新分两种情况:
- 如果你的查询条件里同时包含唯一索引列和分区键,比如
WHERE unique_col='abc' AND created_at='2024-05-01',优化器会先根据created_at定位到目标分区,然后在该分区内通过唯一索引快速找到目标行,效率拉满。 - 如果查询条件里只给了唯一索引列,没给分区键(比如
WHERE unique_col='abc'),那优化器还是得遍历所有分区,在每个分区里用唯一索引查找匹配的行——因为它不知道这个唯一值对应的分区键是啥。
非唯一索引没有必须包含分区键的限制,所以分两种场景:
- 非唯一索引包含分区键:如果查询条件里带了分区键,优化器会先定位到目标分区,然后在分区内走非唯一索引查询/更新;如果没带分区键,还是得遍历所有分区,逐个用索引查找。
- 非唯一索引不包含分区键:不管查询条件里有没有分区键,只要用到这个索引:
- 如果带了分区键,先定位分区,再在分区内扫这个索引;
- 如果没带分区键,就遍历所有分区,每个分区内扫索引,最后合并结果。
如果你想确认自己的查询到底扫了哪些分区,可以用EXPLAIN PARTITIONS命令,比如:
EXPLAIN PARTITIONS SELECT * FROM your_table WHERE id=1234;
在输出的partitions列里,就能看到实际被扫描的分区列表。
内容的提问来源于stack exchange,提问作者Pooya Estakhri




