具有多个OR的多个JOIN非常慢

时间:2016-05-25 09:16:16

标签: mysql performance join conditional-statements

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

关于数据结构:我有对象,可以属于房间,公寓或楼层。一个房间总是属于一个公寓,一个公寓总是属于一个楼层。听起来很复杂,但事实并非如此,这就是层次结构:

  1. 构建(这是我实际需要获取此查询的内容)
  2. 地板
  3. 公寓
  4. 对象(可以属于任何2,3或4)
  5. 这是我目前的查询:

    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秒。可接受的是< .2s,所以它的方式,减缓的方式。

4 个答案:

答案 0 :(得分:0)

如果没有样本数据和预期输出,我无法确定,但根据您的数据,以下内容应该足够了。

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

答案 1 :(得分:0)

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

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

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

由于您似乎担心每个建筑物,地板,公寓和房间的完整性,所以无论实际物体位于任何一个可能的位置,这都应该适合您。

答案 2 :(得分:0)

检查这是否表现更好。

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

答案 3 :(得分:0)

我觉得自己从一开始就没有想出这个解决方案。 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 */

感谢您的所有答案!