索引合并的这些用法,让数据库查询快得飞起

做开发或者维护系统时,经常会遇到查询变慢的问题。比如一个电商后台,要查某个用户在特定时间段内的订单,还按状态筛选。字段一多,查询就卡,这时候光靠单个字段建索引效果有限,就得考虑索引合并了。

什么是索引合并

简单说,索引合并(Index Merge)是MySQL等数据优化器的一种策略:当一条查询涉及多个条件,而每个条件对应不同列的索引时,数据库不再只选一个索引,而是把多个索引的结果取出来,再合并计算出最终数据行。

比如有张订单表 orders,给 user_id 建了索引,又给 order_status 和 created_time 分别建了索引。执行下面这种查询:

SELECT * FROM orders WHERE user_id = 123 AND order_status = 1 AND created_time > '2024-01-01';

如果只走 user_id 的索引,后面还得过滤大量数据;但如果能同时用上三个字段的索引,各自找出符合条件的行ID,再取交集,效率就高多了。

实际使用场景一:后台模糊筛选

运营同事经常要在管理后台查数据。比如想找“北京地区、注册超过一年、最近没登录的用户”。这种组合条件往往跨多个字段,且每个字段都有独立索引。这时候索引合并就能派上用场,不用专门建联合索引也能快速响应。

场景二:日志类数据的多维度查询

像访问日志、操作记录这类表,字段多、数据量大。常需要按时间范围、IP段、操作类型等多个维度查。如果为每种组合都建联合索引不现实,但各个字段单独有索引的话,索引合并可以灵活应对各种查询组合。

注意点:不是什么时候都好用

虽然听起来很香,但索引合并也有代价。它需要读多个索引树,再做交集或并集运算,有时候还不如一个设计合理的联合索引直接扫一遍来得快。

比如还是上面的订单查询,如果高频场景就是 user_id + status + 时间,那不如直接建个联合索引:

ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, order_status, created_time);

这种情况下,走联合索引的效率通常比索引合并更高,还省资源。

怎么判断是否用了索引合并

执行查询前加个 EXPLAIN,看执行计划里的 key 列是不是列出多个索引,或者看到 Extra 里出现 “Using intersect” 或 “Using union”,那就是走了索引合并。

EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND order_status = 1;

如果看到 Using intersect(idx_user, idx_status),说明两个索引被合并使用了。

小建议

日常开发中,别一上来就依赖索引合并。优先考虑高频查询路径,合理设计联合索引。但对于一些低频、临时性的复杂查询,或者字段组合太多无法穷举的情况,索引合并是个不错的兜底方案。

另外,记得定期检查慢查询日志,看看有没有本该走合并却没走的,或者走了合并但依然慢的,结合业务调整索引策略才是正道。