如果在 ON 子句中使用 OR,MySQL 将不会在 JOIN 中使用可用索引
Posted
技术标签:
【中文标题】如果在 ON 子句中使用 OR,MySQL 将不会在 JOIN 中使用可用索引【英文标题】:MySQL won't use available indexes in JOIN if OR is used in ON clause 【发布时间】:2012-03-06 01:02:03 【问题描述】:假设您有 5 个表格,每个表格都有它们的列:
房子(id、name、street_id) 街道(ID、名称) 照片(身份证、姓名) house_photo (house_id, photo_id) street_photo (street_id, photo_id)并说所有 'id' 列和以 '_id' 结尾的列已经有索引。
(实际上我的查询与房屋或街道无关。它们是为了争论。)
现在假设您想将每条街道分成一列,如果那条街道或其房屋有照片,您希望下一列中的照片...
这里的棘手之处在于所有房子都在一张桌子上。以及另一张桌子上的所有照片。但是要链接 2,我们需要访问所有五个表。
我想出了以下查询,包含 4 个 JOIN:
SELECT
street.name
,group_concat(distinct photos.name SEPARATOR '\n') as photos
FROM
house
INNER JOIN street ON
house.street_id = street.id
LEFT JOIN house_photos ON
house.id = house_photos.house_id
LEFT JOIN street_photos ON
street.id = street_photos.street_id
LEFT JOIN photos ON
photos.id = house_photos.photo_id
OR photos.id = street_photos.photo_id
GROUP BY
street.name
distinct 用于过滤掉双打,因为当您有超过 1 张房子的照片和超过 1 张房子街道的照片时会生成它们。 (Carthesian 积)但这与我的问题无关。
我遇到的问题是查询超级慢。 (需要超过 1 分钟甚至更长的时间才能完成)
当我要求 mysql 分析查询('explain extended')时,我发现它在处理最后一个 JOIN(在 ON 子句中有 OR)时不会使用可用索引。
如果我将最后一个 JOIN 拆分为 2 个 JOIN,(从而添加第五个 JOIN),查询再次变得非常快。(需要一秒钟才能完成。)
SELECT
street.name
,concat(
group_concat(distinct photos_from_house.name SEPARATOR '\n')
,'\n'
,group_concat(distinct photos_from_street.name SEPARATOR '\n')
) as photos
FROM
house
INNER JOIN street ON
house.street_id = street.id
LEFT JOIN house_photos ON
house.id = house_photos.house_id
LEFT JOIN street_photos ON
street.id = street_photos.street_id
LEFT JOIN photos photos_from_house ON
photos_from_house.id = house_photos.photo_id
LEFT JOIN photos photos_from_street ON
photos_from_street.id = street_photos.photo_id
GROUP BY
street.name
我现在的问题是:为什么在 ON 子句中引入 OR,使 MySQL 不使用该 JOIN 的可用索引/键?
我已经尝试过使用 USE INDEX 和 FORCE INDEX,但它不会让步。
欢迎任何解释/帮助。
【问题讨论】:
【参考方案1】:The MySQL docs有话要说:
尽量减少 WHERE 子句中的 OR 关键字。如果没有索引 这有助于定位 OR 两侧的值,任何行都可以 可能是结果集的一部分,因此必须测试所有行,并且 这需要全表扫描。如果您有一个索引可以帮助您 优化 OR 查询的一侧,以及有助于 优化另一边,使用 UNION 算子分开跑得快 之后查询并合并结果。
不幸的是,这并不能真正回答您的问题,正如您所说,您在所有相关列上都有索引。
【讨论】:
事实上我认为确实如此......我会等着看是否有更合适的答案出现。但正如你所引用的,我有一个索引用于 OR 的一侧和 1 的另一侧。因此,根据您的报价,我应该使用 UNION 并合并...尽管它确实变得混乱,而且我当前的解决方法(额外的 JOIN)似乎更整洁。以上是关于如果在 ON 子句中使用 OR,MySQL 将不会在 JOIN 中使用可用索引的主要内容,如果未能解决你的问题,请参考以下文章