1

私は2つのテーブルを持っています:

  1. 列がgold_country、silver_country、bronze_countryのolympic_medalists

  2. 国の列のフラグ

それに応じてオリンピックメダル表をリストしたいと思います。私はこのクエリを持っています、それは動作します、しかしそれは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`)
4

2 に答える 2

0

SELECTこれは、相互結合された関係で各行に対して3つの異なるサブクエリを実行する現在のソリューションよりもはるかに効率的です(そして、なぜそれがストールするのか不思議に思うでしょう!):

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、いくつかのコマンドと組み合わせて1つのステートメントで実行できALTER TABLEます。

于 2012-08-04T06:27:59.017 に答える
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
于 2012-08-04T06:36:20.083 に答える