【问题标题】:How to optimize query when using sub-queries in left join在左连接中使用子查询时如何优化查询
【发布时间】:2014-11-23 14:09:26
【问题描述】:

表格: 请在此处查看表格。 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

【问题讨论】:

    标签: mysql sql laravel


    【解决方案1】:

    我相信不用子查询也可以做到。

    我做了下面的比赛表

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

    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
    

    产生以下结果

    请注意,在对一个系列的结果进行分组时,并没有光辉队或可怕队之类的东西。在同一个系列中,光辉和可怕的角色可能会多次互换,所以我只称呼队伍为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
    

    【讨论】:

    • WOOOOOOOOOOH 。而已。你是最好的。非常感谢您 。这个问题已经存在 1 周了 ~_~/ 然后终于出现了。你解决了:非常感谢!
    • 我有问题。如果我想让 radiant_team_id 和 dire_team_id 动态化怎么办?例如,我不想使用团队 ID 过滤掉。
    • 视情况而定。一个系列标识一个独特的团队对?或者它确实解决了一个适用于多个团队对的阶段?除此之外,您还需要考虑有多少逻辑位于模型级别,以及有多少可以通过业务逻辑进行管理。
    • 顺便说一句。谢谢。我现在的问题是如何将其转换为 laravel 查询。 :D
    • 我恐怕没用过 eloquent ORM,不过应该挺简单的
    【解决方案2】:

    可能有更有效的方法来获得您想要的结果。但是,为了使这个查询更有效,您可以添加索引。这是重复的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)。我将从后一个索引开始,看看它是否能充分提高性能以达到您的目的。

    【讨论】:

      猜你喜欢
      • 2020-02-14
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 2017-04-04
      • 1970-01-01
      • 2019-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多