【问题标题】:Multiple JOIN with multiple OR very slow多个 JOIN 与多个 OR 非常慢
【发布时间】:2016-09-22 19:03:45
【问题描述】:

我目前正在编写一个运行良好但速度非常慢的查询。我真的不知道如何进一步加快速度。我没有看到可以设置的任何索引,也没有看到任何更改查询以加快查询速度而不破坏查询的方法。

关于数据结构:我有对象,可以属于房间、公寓或楼层。房间总是属于公寓,公寓总是属于楼层。听起来很复杂但实际上并不复杂,这就是层次结构:

  1. 建筑(这是我实际上必须为这个查询得到的)
  2. 地板
  3. 公寓
  4. 房间
  5. 对象(可以属于任何 2、3 或 4)

这是我目前的查询:

SELECT
  whatever
FROM Object AS o
LEFT JOIN Room AS r AS r.id = o.Room_id
LEFT JOIN Apartment AS a
  ON a.id = o.Apartment_id
  OR a.id = r.Apartment_id
LEFT JOIN Floor AS f
  ON f.id = o.Floor_id
  OR f.id = r.Floor_id
  OR f.id = a.Floor_id
JOIN Building AS b ON b.id = f.Building_id
/* some conditions concerning the Building */

此查询大约需要 17 秒。可以接受的是

【问题讨论】:

  • 请发布一些示例数据
  • 首先,您有几个昂贵的外连接。其次,每个连接都有 OR,这可能无济于事。此外,您应该对查询运行解释计划,您可能会丢失一些索引。

标签: mysql performance join conditional-statements


【解决方案1】:

如果没有样本数据和预期输出,我不能肯定地说,但根据您的数据,以下内容应该足够了。

SELECT *
FROM Building b
INNER JOIN Floor f ON b.id = f.Building_id
INNER JOIN Apartment a ON f.id = a.Floor_id
INNER JOIN Room r ON a.id = r.Apartment_id
INNER JOIN Object o ON r.id = o.Room_id

【讨论】:

  • 这只会让我得到直接属于房间的对象
【解决方案2】:

我将按如下方式处理查询。将查询建筑嵌套到房间作为自然层次结构。在“对象”可能位于楼层、公寓或房间的每个位置,在该特定条件下进行左连接。然后,您的字段列表可以显式引用不同的别名,分别在楼层、公寓或房间中显示。

不知道你的索引,我会建议以下

table      index
building   (id)  -- assume already since it would be PK
floor      (building_id, id)
apartment  (floor_id, id)
room       (apartment_id, id)

对象表,在可能存在的方面 ID 上有 3 个单独的索引

object     (floor_id)
object     (apartment_id)
object     (room_id)

SELECT
      b.id as BuildingID,
      f.id as FloorID,
      COALESCE( FObj.ObjectDescrip, " " ) as FloorObject,
      a.id as ApartmentID,
      COALESCE( AObj.ObjectDescrip, " " ) as ApartmentObject,
      r.id as RoomID,
      COALESCE( RObj.ObjectDescrip, " " ) as RoomObject
   from 
      Building b
         join floor f
            ON b.id = f.building_id
            left join object as FObj
               ON f.id = FObj.floor_id
            left join apartment a
               ON f.id = a.floor_id
               left join object as AObj
                  ON a.id = AObj.apartment_id
               left join room r
                  ON a.id = r.apartment_id
                  left join object as RObj
                     ON r.id = RObj.room_id

由于您似乎关心获取每个建筑物、楼层、公寓和房间的完整性,因此无论实际对象位于任何一个可能的位置,这都应该适合您。

【讨论】:

    【解决方案3】:

    检查这是否表现更好。

    SELECT 
        b.id as Building_id,
        f.id as Floar_id,
        a.id as Apartment_id,
        r.id as Room_id,
        COALESE (ro.Description, ao.Description, fo.Description) as Object_Description
    FROM Building b
    INNER JOIN Floor f ON b.id = f.Building_id
    INNER JOIN Apartment a ON f.id = a.Floor_id
    INNER JOIN Room r ON a.id = r.Apartment_id
    LEFT JOIN Object ro ON r.id = ro.Room_id
    LEFT JOIN Object ao on a.id = ao.Apartment_id
    LEFT JOIN Object fo on f.id = fo.Floar_id
    

    【讨论】:

      【解决方案4】:

      我觉得自己是个白痴,因为我没有从一开始就想出这个解决方案。连接到公寓的 ON 子句中的一个简单 IF 语句对我有用:

      SELECT
        whatever
      FROM Object AS o
      LEFT JOIN Room AS r ON r.id = o.Room_id
      LEFT JOIN Apartment AS a
        /* This solved it */
        ON a.id = IF(o.Apartment_id IS NULL, r.Apartment_id, o.Apartment_id)
      LEFT JOIN Floor AS f
        ON f.id = o.Floor_id
        OR f.id = r.Floor_id
        OR f.id = a.Floor_id
      JOIN Building AS b ON b.id = f.Building_id
      /* some conditions concerning the Building */
      

      感谢您的所有回答!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        • 1970-01-01
        • 2021-04-05
        • 2019-02-06
        • 2015-05-20
        • 1970-01-01
        • 2012-07-13
        相关资源
        最近更新 更多