3

假设您有 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

独特之处在于过滤掉双打,因为当你有超过 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,但它不会让步。

欢迎任何解释/帮助。

4

1 回答 1

4

MySQL 文档有这样的说法:

尽量减少 WHERE 子句中的 OR 关键字。如果没有索引可以帮助定位 OR 两侧的值,则任何行都可能成为结果集的一部分,因此必须测试所有行,这需要进行全表扫描。如果您有一个有助于优化 OR 查询一侧的索引和一个有助于优化另一侧的不同索引,请使用 UNION 运算符运行单独的快速查询并随后合并结果。

不幸的是,这并不能真正回答您的问题,正如您所说,您在所有相关列上都有索引。

于 2012-02-14T17:48:01.627 回答