添加依赖连接时MySQL连接不使用索引

问题描述 投票:0回答:1

当我对以下查询执行 EXPLAIN 来获取预订的用户时

SELECT user.id
FROM user
    LEFT JOIN booking
        ON booking.user_id = user.id
            AND booking.end_timestamp > 1706878800
            AND booking.end_timestamp <= 1706882400
            AND booking.status IN ('pending', 'progress', 'done');

我得到以下结果:

id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 简单 用户 索引 状态 1 17644 100 使用索引
1 简单 预订 参考 状态,user_id_start_timestamp,user_id_status_end_timestamp,end_timestamp 用户 ID 状态结束时间戳 5 db.user.id 403 0.01 使用地点;使用索引

如您所见,它会自动使用

user_id_status_end_timestamp
表的索引
booking

但是当我向查询添加另一个联接以包含

address
时,这取决于
booking
表:

SELECT user.id
FROM user
    LEFT JOIN booking
        ON booking.user_id = user.id
            AND booking.end_timestamp > 1706878800
            AND booking.end_timestamp <= 1706882400
            AND booking.status IN ('pending', 'progress', 'done')
    LEFT JOIN address ON booking.address_id = address.id;

现在它不再对

booking
表使用任何索引,使得查询非常慢,即使它显示了相同的可能键列表:

id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 简单 用户 索引 状态 1 17644 100 使用索引
1 简单 预订 全部 状态,user_id_start_timestamp,user_id_status_end_timestamp,end_timestamp 9509525 100 检查每条记录的范围(索引图:0x98040)
1 简单 地址 eq_ref 小学 小学 4 db.booking.address_id 1 100 使用索引

当然,如果我添加

USE INDEX (user_id_status_end_timestamp)
,它可以工作,但为什么MySQL在这种情况下不自动使用索引?

我使用的是 MySQL 版本 5.7.42。

mysql left-join query-optimization
1个回答
0
投票

删除

LEFTs
,它们对于您的应用来说似乎“错误”。

bookings
需要

INDEX(end_timestamp, status),
INDEX(status, end_timestamp)

由于您要过滤日期和状态,因此这应该是第一个要使用的表,但

LEFT
阻止了这种情况。相反,您将获得所有用户,以及其他表中的 NULL。

优化器将根据表统计信息和提供的值在这些索引之间进行选择。

© www.soinside.com 2019 - 2024. All rights reserved.