如何在左连接中使用子查询时优化查询

时间:2014-11-23 14:09:27

标签: mysql sql laravel

表格: 请看这里查看表格。 How to query counting specific wins of team and find the winner of the series

问题:

  • 如何使查询更优化?
  • 如何减少查询冗余?
  • 如何更快地进行此查询?

摘要

正如您在示例查询中看到的那样,此部分使用了很多次。

WHERE leagueid = 2096
AND start_time >= 1415938900
AND ((matches.radiant_team_id= 1848158 AND matches.dire_team_id= 15)
OR (matches.radiant_team_id= 15 AND matches.dire_team_id= 1848158))

SELECT matches.radiant_team_id,
       matches.dire_team_id,
       matches.radiant_name,
       matches.dire_name,
       TA.Count AS teamA,
       TB.Count AS teamB,
       TA.Count + TB.Count AS total_matches,
       SUM(TA.wins),
       SUM(TB.wins),
       (CASE
            WHEN series_type = 0 THEN 1
            WHEN series_type = 1 THEN 2
            WHEN series_type = 2 THEN 3
        END) AS wins_goal
FROM matches
LEFT JOIN
  (SELECT radiant_team_id,
          COUNT(id) AS COUNT,
          CASE
              WHEN matches.radiant_team_id = radiant_team_id && radiant_win = 1 THEN 1
          END AS wins
   FROM matches
   WHERE leagueid = 2096
     AND start_time >= 1415938900
     AND ((matches.radiant_team_id= 1848158
           AND matches.dire_team_id= 15)
          OR (matches.radiant_team_id= 15
              AND matches.dire_team_id= 1848158))
   GROUP BY radiant_team_id) AS TA ON TA.radiant_team_id = matches.radiant_team_id
LEFT JOIN
  (SELECT dire_team_id,
          COUNT(id) AS COUNT,
          CASE
              WHEN matches.dire_team_id = dire_team_id && radiant_win = 0 THEN 1
          END AS wins
   FROM matches
   WHERE leagueid = 2096
     AND start_time >= 1415938900
     AND ((matches.radiant_team_id= 1848158
           AND matches.dire_team_id= 15)
          OR (matches.radiant_team_id= 15
              AND matches.dire_team_id= 1848158))
   GROUP BY dire_team_id) AS TB ON TB.dire_team_id = matches.dire_team_id
WHERE leagueid = 2096
  AND start_time >= 1415938900
  AND ((matches.radiant_team_id= 1848158
        AND matches.dire_team_id= 15)
       OR (matches.radiant_team_id= 15
           AND matches.dire_team_id= 1848158))
GROUP BY series_id

预定匹配

ID| leagueid| team_a_id| team_b_id| starttime
 1|     2096|   1848158|        15| 1415938900

2 个答案:

答案 0 :(得分:1)

可能有更有效的方法来获得您想要的结果。但是,为了使此查询更有效,您可以添加索引。这是重复的where子句:

WHERE leagueid = 2096 AND
      start_time >= 1415938900 AND
      ((matches.radiant_team_id= 1848158 AND matches.dire_team_id= 15) OR
       (matches.radiant_team_id= 15 AND matches.dire_team_id= 1848158))

or的条件对于优化器来说很难。以下索引将有所帮助:matches(leagueid, start_time)。覆盖索引(至少为where条件)为matches(leagueid, start_time, radiant_team_id, dire_team_id)。我将从后一个索引开始,看看是否能够为您的目的充分提高性能。

答案 1 :(得分:1)

我相信没有子查询就可以完成。

我制作了以下比赛表

enter image description here

并使用以下查询对结果进行分组,每个系列一行

SELECT 
      matches.leagueid,
      matches.series_id,
      matches.series_type,
      COUNT(id) as matches,
      IF(radiant_team_id=1848158,radiant_name, dire_name) AS teamA,
      IF(radiant_team_id=1848158,dire_name, radiant_name) AS teamB,
      SUM(CASE
           WHEN radiant_team_id=1848158 AND radiant_win=1  THEN 1
           WHEN dire_team_id=1848158 AND radiant_win=0 THEN 1
           ELSE 0 END) AS teamAwin,
      SUM(CASE
           WHEN radiant_team_id=15 AND radiant_win=1  THEN 1
           WHEN dire_team_id=15 AND radiant_win=0 THEN 1
           ELSE 0 END) AS teamBwin

FROM `matches` 
WHERE leagueid = 2096
     AND start_time >= 1415938900
AND dire_team_id IN (15, 1848158)
AND radiant_team_id IN  (15, 1848158)
group by leagueid,series_id,series_type,teamA,teamB

产生以下结果

enter image description here

请注意,在对一个系列的结果进行分组时,不存在辐射团队或可怕团队的事情。在同一系列中,radiant和dire角色可能会多次切换,因此我只将团队称为teamA和teamB。

现在,看看你之前的问题,我发现你需要根据系列赛类型和每支球队的胜利确定系列赛冠军。这需要包装前一个查询并将其用作子查询,例如

SELECT matchresults.*,
      CASE series_type
      WHEN 0 then IF(teamAwin>=1, teamA,teamB)
      WHEN 1 then IF(teamAwin>=2, teamA,teamB)
      ELSE IF(teamAwin>=3, teamA,teamB)
      END as winner

from ( THE_MAIN_QUERY) as matchresults