优化mysql查询:奖牌榜

时间:2012-08-04 05:42:54

标签: mysql optimization

我有两张桌子:

  1. 奥林匹克运动员,栏目为gold_country,silver_country,bronze_country

  2. 国家/地区列标志

  3. 我想相应地列出奥运奖牌榜。我有这个查询,它的工作原理,但似乎杀了mysql。希望有人可以帮助我优化查询。

    SELECT DISTINCT country AS sc,
        IFNULL(
            (SELECT COUNT(silver_country) 
                FROM olympic_medalists 
            WHERE silver_country = sc AND silver_country != '' 
            GROUP BY silver_country),0) AS silver_medals, 
        IFNULL(
            (SELECT COUNT(gold_country) 
                FROM olympic_medalists 
            WHERE gold_country = sc AND gold_country != '' 
            GROUP BY gold_country),0) AS gold_medals,
        IFNULL(
            (SELECT COUNT(bronze_country) 
                FROM olympic_medalists 
            WHERE bronze_country = sc AND bronze_country != '' 
            GROUP BY bronze_country),0) AS bronze_medals
    FROM olympic_medalists, flags 
    GROUP BY country, gold_medals, silver_country, bronze_medals HAVING (
        silver_medals >= 1 || gold_medals >= 1 || bronze_medals >= 1)
    ORDER BY gold_medals DESC, silver_medals DESC, bronze_medals DESC,   
    SUM(gold_medals+silver_medals+bronze_medals)
    

    结果将如下:

    country  |  g  |  s  |  b  |  tot
    ---------------------------------
    country1 |  9  |  5  |  2  |  16
    country2 |  5  |  5  |  5  |  15
    

    等等

    谢谢!

    olympic medalists:
    
      `id` int(8) NOT NULL auto_increment,
      `gold_country` varchar(64) collate utf8_unicode_ci default NULL,
      `silver_country` varchar(64) collate utf8_unicode_ci default NULL,
      `bronze_country` varchar(64) collate utf8_unicode_ci default NULL, PRIMARY KEY  (`id`)
    
    flags
    
      `id` int(11) NOT NULL auto_increment,
      `country` varchar(128) default NULL,
      PRIMARY KEY  (`id`)
    

2 个答案:

答案 0 :(得分:0)

这比您在交叉连接关系中为每一行执行三个不同SELECT子查询的当前解决方案更有效(并且您想知道为什么它会停止!):

SELECT    a.country,
          COALESCE(b.cnt,0)     AS g,
          COALESCE(c.cnt,0)     AS s,
          COALESCE(d.cnt,0)     AS b,
          COALESCE(b.cnt,0) +
          COALESCE(c.cnt,0) +
          COALESCE(d.cnt,0)     AS tot
FROM      flags a
LEFT JOIN (
          SELECT   gold_country, COUNT(*) AS cnt 
          FROM     olympic_medalists 
          GROUP BY gold_country
          ) b ON a.country = b.gold_country
LEFT JOIN (
          SELECT   silver_country, COUNT(*) AS cnt 
          FROM     olympic_medalists 
          GROUP BY silver_country
          ) c ON a.country = c.silver_country
LEFT JOIN (
          SELECT   bronze_country, COUNT(*) AS cnt 
          FROM     olympic_medalists 
          GROUP BY bronze_country
          ) d ON a.country = d.bronze_country

更快的是,不是在每个金色,银色和铜色列中存储实际的文本国家名称,只需存储基于整数的国家/地区id。对整数的比较总是比对字符串的比较更快。

此外,一旦将olympic_medalists表中的每个国家/地区名称替换为相应的ID,您就需要在每个列(金,银和铜牌)上创建索引。

将文本名称更新为相应的id是一项简单的任务,可以使用单个UPDATE语句和一些ALTER TABLE命令来完成。

答案 1 :(得分:0)

试试这个:

SELECT F.COUNTRY,IFNULL(B.G,0) AS G,IFNULL(B.S,0) AS S,
IFNULL(B.B,0) AS B,IFNULL(B.G+B.S+B.B,0) AS TOTAL
FROM FLAGS F LEFT OUTER JOIN
      (SELECT A.COUNTRY,
         SUM(CASE WHEN MEDAL ='G' THEN 1 ELSE 0 END) AS G,
         SUM(CASE WHEN MEDAL ='S' THEN 1 ELSE 0 END) AS S,
         SUM(CASE WHEN MEDAL ='B' THEN 1 ELSE 0 END) AS B
      FROM   
          (SELECT GOLD_COUNTRY AS COUNTRY,'G' AS MEDAL 
           FROM OLYMPIC_MEDALISTS WHERE GOLD_COUNTRY IS NOT NULL
           UNION ALL
           SELECT SILVER_COUNTRY AS COUNTRY,'S' AS MEDAL 
           FROM OLYMPIC_MEDALISTS WHERE SILVER_COUNTRY IS NOT NULL
           UNION ALL
           SELECT BRONZE_COUNTRY AS COUNTRY,'B' AS MEDAL 
           FROM OLYMPIC_MEDALISTS WHERE BRONZE_COUNTRY IS NOT NULL)A
      GROUP BY A.COUNTRY)B
 ON F.COUNTRY=B.COUNTRY
 ORDER BY IFNULL(B.G,0) DESC,IFNULL(B.S,0) DESC,
          IFNULL(B.B,0) DESC,IFNULL(B.G+B.S+B.B,0) DESC,F.COUNTRY