分区裁剪需显式where时间条件,否则不触发;索引失效主因是函数、隐式转换或类型不一致;复合索引应按高选择性字段+范围字段顺序设计;区间join宜用窗口函数替代暴力join。

WHERE没加时间范围,分区裁剪根本不会触发
分区表不是建了就自动裁剪的。MySQL、PostgreSQL 都依赖 WHERE 子句中显式的时间约束来推导可排除的分区。如果只写 JOIN 条件而漏掉 WHERE o.event_time >= '2026-07-01' AND o.event_time ,优化器连哪几个分区该扫都不知道,直接全扫。
常见错误写法包括:
-
WHERE DATE(o.event_time) = '2026-07-15'—— 函数导致分区裁剪和索引同时失效 -
WHERE o.event_time + INTERVAL 1 DAY = '2026-07-16'—— 表达式破坏字段原始值,无法定位分区 -
WHERE o.event_time BETWEEN '2026-07-01' AND '2026-07-31 23:59:59'—— 闭区间易因秒级精度丢失边界,建议改用开区间
JOIN条件里缺分区键或时间重叠表达式,右表照样全扫
左表靠 WHERE 裁剪完,右表还得自己“收敛”。如果右表按 valid_from 分区,但 JOIN 只写 o.user_id = p.user_id,那右表每个分区都得查一遍。
正确做法是让 JOIN 条件本身带时间维度约束:
- 支持区间匹配:
ON o.order_time BETWEEN p.valid_from AND p.valid_until - 确保右表有
INDEX (valid_from, valid_until),且分区键是valid_from - 避免写成:
ON o.order_time >= p.valid_from - INTERVAL 1 HOUR—— 表达式让索引无法用于范围扫描 - 字段类型必须一致:左表
DATETIME,右表不能是TIMESTAMP,否则隐式转换废掉裁剪能力
MySQL 8.0 用 ROW_NUMBER() 替代暴力区间 JOIN
MySQL 不支持 LATERAL,也没原生区间 JOIN 优化,硬写 BETWEEN 容易触发嵌套循环+全表扫描。这时候窗口函数是更可控的替代方案。
典型写法分两步:
- 先做笛卡尔交集:
FROM orders o JOIN prices p ON o.order_time >= p.valid_from AND o.order_time - 再用
ROW_NUMBER() OVER (PARTITION BY o.order_id ORDER BY p.valid_from DESC)标序,外层取rn = 1 - 关键点:
ORDER BY字段必须是索引前缀,否则排序代价爆炸;valid_from索引必须存在 - 别用
GROUP BY + MAX()替代,容易丢字段、语义不稳
索引顺序不匹配扫描模式,等于白建
建了 INDEX (event_time) 还是慢?可能是因为查询实际走的是 WHERE event_time > ? AND status = ?,而单列索引无法覆盖 status 过滤。
复合索引设计要贴合真实扫描路径:
- 高选择性字段(如
user_id)放最左,范围查询字段(如event_time)放右 - 区间 JOIN 场景下,优先建
INDEX (valid_from, valid_until),而不是分开两个单列索引 -
EXPLAIN中若出现type: ALL或rows高得离谱,先看key列是否为NULL,再核对索引定义与 WHERE/JON 条件的字段顺序是否对齐
时间字段上的函数、隐式转换、类型不一致,三者任一出现,索引和分区裁剪都会同时失效——不是“可能慢”,是“必然退化”。











