MySQL为何未使用notification_id_tag_value_recipient_brand联合索引?
notification_id_tag_value_recipient_brand联合索引 1. 违背联合索引最左前缀原则
你的联合索引起始列为notification_id,但查询语句中完全没有涉及该列的过滤条件。MySQL联合索引遵循最左前缀匹配规则,必须从索引的第一列开始匹配才能有效利用索引,跳过起始列后,索引的有序性被破坏,无法发挥联合索引的过滤优势。
2. 联合索引列顺序与查询匹配效率低
即便忽略起始列,联合索引中tag_value位于第二列,recipient在第三列,brand在第四列。由于缺少notification_id的筛选,索引内的tag_value是分散在不同notification_id分组下的,此时用联合索引查找tag_value='doc1'的效率,远低于专门针对tag_value建立的单值索引——单值索引是完全按tag_value排序的,能快速定位目标数据。
3. brand条件的过滤成本高
查询中的(brand='brand' or brand is null)是多分支条件,且brand是联合索引的最后一列。在没有前面列(尤其是notification_id)精准匹配的前提下,MySQL需要在扫描到的tag_value和recipient匹配行中,额外过滤两种brand情况,这会增加索引扫描的计算成本。相比之下,用单值索引定位tag_value后,在内存中过滤recipient和brand的成本更低。
4. 优化器的成本评估结果
MySQL优化器会对比不同索引的使用成本,包括索引扫描行数、回表开销等。由于联合索引无法利用最左前缀,扫描的索引行数远多于单值索引,再加上后续过滤的额外成本,优化器最终选择了成本更低的tag_value单值索引。
如果希望查询使用联合索引,可以调整索引列顺序,例如创建tag_value, recipient, brand, notification_id这样的联合索引,让查询条件能匹配索引的最左前缀,从而充分利用联合索引的过滤能力。
内容的提问来源于stack exchange,提问作者Lakmal

