关于MySQL单列索引与联合索引使用的技术咨询
关于数据库索引使用的两个问题解答
刚好对数据库索引优化这块摸得门清,给你详细拆解下这两个问题:
问题1:多条件WHERE子句下,三个单列索引会同时被使用吗?
- 先给你敲黑板:绝大多数场景下,数据库优化器不会同时用这三个单列索引,除非你的数据分布和过滤条件刚好触发了「索引合并(Index Merge)」机制,但这种情况真的不多见。
- 拿MySQL举例,如果这三个字段的过滤能力都极强(比如每个条件都能筛掉90%以上的数据),优化器可能会用
Index Merge Intersection的方式——分别通过三个单列索引找到符合条件的行集合,再取交集得到最终结果。但这种操作的成本其实很高:数据库要分别扫描三个索引,还要做交集运算,很多时候还不如直接用一个区分度最高的单列索引(比如username,如果它的唯一值最多),先快速定位行,再在结果里过滤另外两个条件来得高效。 - 真心话:如果你的业务经常需要同时用这三个字段做查询,直接创建这三个字段的联合索引(顺序按区分度从高到低排)才是最优解,比赌优化器触发索引合并靠谱多了。
问题2:联合索引中,仅指定最左列和最后一列,能用到最后一列的索引部分吗?
- 答案很明确:不能,这涉及到联合索引的核心规则——最左前缀原则。
- 联合索引的存储逻辑是按列的顺序逐层排序的,比如你创建的
(username, country, created_at, comment, status)联合索引,排序优先级是:先按username排序,同一个username下按country排序,以此类推,最后才轮到status。 - 当你的
WHERE子句只指定username和status时,数据库确实能通过username快速定位到所有该用户的行,但这些行的status在索引里是完全无序的(因为中间的country、created_at、comment都没指定,同一个username下的行是按后面几列排序的,status并没有单独形成有序的结构)。所以数据库没办法直接用索引过滤status,只能先通过username拿到匹配的行,再逐一检查status是否符合条件。 - 总结下:联合索引里,只有当你使用了从最左开始的连续前缀列时,后面的列才能被索引利用。跳过中间列的话,后面的列就完全发挥不了索引的作用了。
内容的提问来源于stack exchange,提问作者areviews app
相关产品推荐
相关产品推荐

