MySQL没有从RIGHT JOIN优化IS NULL子句

时间:2015-04-14 09:52:25

标签: mysql join

我在优化IS NULL检查联接表时遇到了一个具有挑战性的问题。

在以下查询中,您会看到我RIGHT JOIN calendar表。只要我不检查calendar.time is null,查询就能完美运行。

select `teams`.`name` as `label`, `teams`.`id` as `id`, count(`teams`.`id`) as value 
from `likes` 

right join `calendar` on `calendar_id` = `calendar`.`id` 

left join `profile_team` on `likes`.`profile_id` = `profile_team`.`profile_id` 

right join `teams` on `profile_team`.`team_id` = `teams`.`id` 

where (
  `calendar`.`time` between '2015-02-14' and '2015-04-14' 
  or `calendar`.`time` is null
) 

group by `teams`.`id`;

小提琴:http://sqlfiddle.com/#!9/200c0/7


查询的想法是返回teams的每一行,即使likes没有相关的行。 likesteams通过likes.profile_idprofile_team.profile_idprofile_team.team_idteams.id相关联。

UML diagram

calendar已加入,因为它包含按时间过滤数据集的参考点。


感谢您的帮助。


修改:EXPLAIN输出:

使用IS NULL

| id | select_type |        table |   type |       possible_keys |                 key | key_len |                          ref | rows |                    Extra |
|----|-------------|--------------|--------|---------------------|---------------------|---------|------------------------------|------|--------------------------|
|  1 |      SIMPLE |        teams |  index |             PRIMARY |             PRIMARY |       4 |                       (null) |    1 |                   (null) |
|  1 |      SIMPLE | profile_team |  index | profile_team_unique | profile_team_unique |       8 |                       (null) |    1 | Using where; Using index |
|  1 |      SIMPLE |        likes |    ALL |         calendar_id |              (null) |  (null) |                       (null) |    8 |              Using where |
|  1 |      SIMPLE |     calendar | eq_ref |             PRIMARY |             PRIMARY |       4 | db_9_200c0.likes.calendar_id |    1 |              Using where |

没有IS NULL

| id | select_type |        table |   type |       possible_keys |                 key | key_len |                             ref | rows |                                                     Extra |
|----|-------------|--------------|--------|---------------------|---------------------|---------|---------------------------------|------|-----------------------------------------------------------|
|  1 |      SIMPLE |     calendar |  range |        PRIMARY,time |                time |       4 |                          (null) |    1 | Using where; Using index; Using temporary; Using filesort |
|  1 |      SIMPLE |        likes |    ref |         calendar_id |         calendar_id |       5 |          db_9_200c0.calendar.id |    1 |                                                    (null) |
|  1 |      SIMPLE | profile_team |    ref | profile_team_unique | profile_team_unique |       4 |     db_9_200c0.likes.profile_id |    1 |                                  Using where; Using index |
|  1 |      SIMPLE |        teams | eq_ref |             PRIMARY |             PRIMARY |       4 | db_9_200c0.profile_team.team_id |    1 |                                               Using where |

1 个答案:

答案 0 :(得分:0)

请尝试此查询:

SELECT
    `teams`.`name` as `label`, `teams`.`id` as `id`
FROM
    `teams` 
    LEFT JOIN
    `profile_team` ON `teams`.`id` = `profile_team`.`team_id`
    LEFT JOIN
    `likes` ON `profile_team`.`profile_id` = `likes`.`profile_id`
    LEFT JOIN
    `calendar` ON `likes`.`calendar_id` = `calendar`.`id`
            AND
            `calendar`.`time` BETWEEN '2015-02-14' AND '2015-04-14'
UNION ALL
SELECT
    `teams`.`name` as `label`, `teams`.`id` as `id`
FROM
    `teams` 
    LEFT JOIN
    `profile_team` ON `teams`.`id` = `profile_team`.`team_id`
    LEFT JOIN
    `likes` ON `profile_team`.`profile_id` = `likes`.`profile_id`
    LEFT JOIN
    `calendar` ON `likes`.`calendar_id` = `calendar`.`id`
            AND
            IFNULL(`calendar`.`time`, 0) = 0

我现在无法测试;)。


我在做什么?

  1. 根据基表(teams)制作联接顺序,所以我只有LEFT JOIN
  2. 当我建议使用WHERE时删除JOIN
  3. OR替换UNION ALL以获得更好的效果。
  4. 使用IFNULL代替IS NULL