我正在查询我的数据库,查找教师主要位置的位置列表或教师提供可用性信息的位置。
如果我这样做两个连接:
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的速度快?结果数据相同。
答案 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;