为什么两个连接比具有OR条件的连接运行得更快?

时间:2014-04-28 17:52:46

标签: mysql conditional left-join

我正在查询我的数据库,查找教师主要位置的位置列表或教师提供可用性信息的位置。

如果我这样做两个连接:

SELECT tea.*, avail_loc.*, pri_loc.*
FROM teachers AS tea
     LEFT JOIN availability AS ava
            ON(tea.teacher_id = ava.teacher_id AND ava.end_date > 1398706428)
     LEFT JOIN locations AS avail_loc
            ON(ava.location_id = avail_loc.location_id)
     LEFT JOIN locations AS pri_loc
            ON(tea.location_id = pri_loc.location_id)
WHERE tea.active = 1

我的查询需要.05秒。问题是我必须清理php中的输出,因为我的位置分为avail_loc(备用位置)和pri_loc(主要位置)。

因此,如果我将它们组合成一个带OR条件的连接,则查询需要0.8秒。

SELECT tea.*, loc.*
FROM teachers AS tea
     LEFT JOIN availability AS ava
            ON(tea.teacher_id = ava.teacher_id AND ava.end_date > 1398706428)
     LEFT JOIN locations AS loc
            ON(ava.location_id = loc.location_id OR tea.location_id = loc.location_id)
WHERE tea.active = 1

当我使用EXPLAIN时,第一个查询具有匹配所有内容的索引。当我运行第二个查询时,它缺少OR连接的连接。

为什么两个连接速度比带OR的速度快?结果数据相同。

1 个答案:

答案 0 :(得分:2)

首先,这两个查询不相同。如果每个表中都有一个匹配项,那么第一个将返回一行,第二个将返回两行。

但问题的答案是优化问题。 MySQL在or条件下进行优化的能力很差。正如您所注意到的,它错过了可以使用不同索引来满足每个条件的事实。说实话,这是大多数数据库引擎的问题。如果您希望or的效果具有更好的效果,那么union all通常效果会更好:

SELECT tea.*, loc.*
FROM teachers AS tea
     LEFT JOIN availability AS ava
            ON(tea.teacher_id = ava.teacher_id AND ava.end_date > 1398706428)
     LEFT JOIN locations AS loc
            ON(tea.location_id = loc.location_id)
WHERE tea.active = 1
union all
SELECT tea.*, loc.*
FROM teachers AS tea
     LEFT JOIN availability AS ava
            ON(tea.teacher_id = ava.teacher_id AND ava.end_date > 1398706428)
     LEFT JOIN locations AS loc
            ON(ava.location_id = loc.location_id)
WHERE tea.active = 1;