优化MySQL查询,选择中选择,相同的多个

优化MySQL查询,选择中选择,相同的多个,mysql,sql,optimization,Mysql,Sql,Optimization,我需要帮助优化我创建的MySQL语句。它正是我想要的,但是我有一种很好的感觉,它会非常慢,因为我在语句中进行了多次选择,并且我还多次查询新的。这是我第一次做这样的重要陈述,我习惯了简单的从哪里选择风格垃圾 我可能会做一些解释,这是一个排行榜风格的东西为我的网站 -第一个变量输出是根据所示公式计算的排名,Log+Log+成就 -Wepvalue是该id拥有的武器值的总和。playerweapons包含所有武器,武器价格将类型转换为价格,然后总和计算值 -Achcount只是解锁的成就数量。也许这可

我需要帮助优化我创建的MySQL语句。它正是我想要的,但是我有一种很好的感觉,它会非常慢,因为我在语句中进行了多次选择,并且我还多次查询新的。这是我第一次做这样的重要陈述,我习惯了简单的从哪里选择风格垃圾

我可能会做一些解释,这是一个排行榜风格的东西为我的网站

-第一个变量输出是根据所示公式计算的排名,Log+Log+成就

-Wepvalue是该id拥有的武器值的总和。playerweapons包含所有武器,武器价格将类型转换为价格,然后总和计算值

-Achcount只是解锁的成就数量。也许这可以通过排名输出进行优化

-成就中的id\u new和playerweapons是playerdata中id的外键

表结构:

玩家数据:

新成就:

武器价格:


提前谢谢

试试下面的查询。 我使用左连接而不是连接,因为可能有没有成就或武器的球员。如果你不需要这些球员,你可以使用加入

SELECT
    IFNULL(LOG(1.5, p.cashearned),0) +
        IFNULL(LOG(1.3, p.roundswon), 0) +
        SUM(CASE WHEN ac.id IS NOT NULL THEN 1 ELSE 0 END)/COUNT(pw.id) as rank
    p.nationality,
    p.nick,
    p.steamid64,
    p.cash,
    p.playtime,
    p.damage,
    p.destroyed,
    --SUM(CASE WHEN pw.id IS NOT NULL THEN pw.price ELSE 0 END) as wepvalue,
    --wpn.price as wepvalue,
    SUM(CASE WHEN pw.id IS NOT NULL THEN wp.price ELSE 0 END)/COUNT(ac.id) as wepvalue,
    SUM(CASE WHEN ac.id IS NOT NULL THEN 1 ELSE 0 END)/COUNT(pw.id) as achcount,
    lastplayed
FROM playerdata as p
    JOIN playerweapons as pw ON pw.id = p.id
    JOIN weaponprices as wp ON pw.class = wp.weapon
    LEFT JOIN achievements_new as ac ON ac.id = p.id AND ac.value = -1
    --LEFT JOIN playerweapons as pw ON pw.id = p.id
    --LEFT JOIN weaponprices as wp ON pw.class = wp.weapon
    --LEFT JOIN (   SELECT 
                      --pw.id as player,
                      --SUM(wp.price) as price
                  --FROM weaponprices as wp
                      --JOIN playerweapons as pw ON pw.class = wp.weapon 
                  --GROUP BY pw.id
              --) as wpn ON wpn.player = p.id
GROUP BY 
    p.nationality,
    p.nick,
    p.steamid64,
    p.cash,
    p.playtime,
    p.damage,
    p.destroyed,
    p.lastplayed

您的查询是相当合理的,尽管我会重写子查询以使用显式连接,而不是在子查询中使用in和factor out:

SELECT (IFNULL(LOG(1.5, cashearned),0) + IFNULL(LOG(1.3, roundswon), 0) +
        coalesce(an.cnt, 0)
       ) as rank,
       nationality, nick, steamid64, cash, playtime, damage, destroyed,
       (SELECT SUM(wp.price)
        FROM weaponprices wp JOIN
             playerweapons pw
             on pw.class = wp.weapons
        WHERE pw.id = pd.id
       ) as wepvalue,
       coalesce(an.cnt, 0) as achcount,
       lastplayed
FROM playerdata pd left outer join
     (SELECT id, count(*) as cnt
      FROM achievements_new an
      WHERE an.`value` = -1 
      GROUP BY an.id
     ) an
     on an.id = pd.id
ORDER BY rank DESC;
对于此查询,请创建以下索引:

playerweapons(id, weapon);
weaponprices(class, price);
achievements_new(value, id);
这将实现以下功能:

它消除了两个冗余的子查询。 它应该优化prices子查询,使其仅使用索引。 它用显式联接替换in,这有时会得到更好的优化。 它不需要外部分组。
我将尝试删除所有相关的子查询

SELECT
      ( COALESCE(LOG(1.5, pd.cashearned), 0)
      + COALESCE(LOG(1.3, pd.roundswon), 0)
      + COALESCE(an.cnt, 0))   AS rank
    , pd.nationality
    , pd.nick
    , pd.steamid64
    , pd.cash
    , pd.playtime
    , pd.damage
    , pd.destroyed
    , COALESCE(pw.wepvalue, 0) AS wepvalue
    , COALESCE(an.cnt, 0)      AS achcount
    , pd.lastplayed
FROM playerdata pd
      LEFT JOIN (
                  SELECT
                        id
                      , COUNT(*) AS cnt
                  FROM achievements_new
                  WHERE value = -1
                  GROUP BY
                        id
            ) an
                  ON pd.id = an.id
      LEFT JOIN (
                  SELECT
                        playerweapons.id
                      , SUM(price) AS wepvalue
                  FROM weaponprices
                        INNER JOIN playerweapons
                                    ON weaponprices.weapon = playerweapons.class
                  GROUP BY
                        playerweapons.id
            ) pw
                  ON pd.id = pw.id
ORDER BY
      rank DESC;

还显示解释。可以将带有IN的子查询编写为联接。使用联接而不是子查询将是更好的选择。我知道联接,只是不知道在这种情况下如何正确使用它们。看来您完全错过了武器价格表,否则这看起来不错!不知道为什么,但调用此查询后,我的整个MySQL服务器冻结,不得不强制重新启动它:-从头开始——它似乎会导致所有总和出现极值,wepvalue高达1000万,最大可能为315k。Achcount最多有数百个,最大值为31。无论何时使用SUM、AVG或COUNT等聚合函数,都需要使用该子句。这是因为每个玩家都可以有多个成就和武器。假设一个玩家拥有m件武器和n项成就,那么武器价格将是每件武器的价格。一个解决办法是除以成就的数量。我将把它添加到答案中。我相信,class应该读到wp.wearm=wp.class。但出于好奇:为什么要保留这个相关子查询?@Used\u By\u已经。我相信你是对的。非常感谢。
CREATE TABLE IF NOT EXISTS `weaponprices` (
  `weapon` varchar(30) NOT NULL,
  `price` int(10) unsigned NOT NULL
) ENGINE=InnoDB
SELECT
    IFNULL(LOG(1.5, p.cashearned),0) +
        IFNULL(LOG(1.3, p.roundswon), 0) +
        SUM(CASE WHEN ac.id IS NOT NULL THEN 1 ELSE 0 END)/COUNT(pw.id) as rank
    p.nationality,
    p.nick,
    p.steamid64,
    p.cash,
    p.playtime,
    p.damage,
    p.destroyed,
    --SUM(CASE WHEN pw.id IS NOT NULL THEN pw.price ELSE 0 END) as wepvalue,
    --wpn.price as wepvalue,
    SUM(CASE WHEN pw.id IS NOT NULL THEN wp.price ELSE 0 END)/COUNT(ac.id) as wepvalue,
    SUM(CASE WHEN ac.id IS NOT NULL THEN 1 ELSE 0 END)/COUNT(pw.id) as achcount,
    lastplayed
FROM playerdata as p
    JOIN playerweapons as pw ON pw.id = p.id
    JOIN weaponprices as wp ON pw.class = wp.weapon
    LEFT JOIN achievements_new as ac ON ac.id = p.id AND ac.value = -1
    --LEFT JOIN playerweapons as pw ON pw.id = p.id
    --LEFT JOIN weaponprices as wp ON pw.class = wp.weapon
    --LEFT JOIN (   SELECT 
                      --pw.id as player,
                      --SUM(wp.price) as price
                  --FROM weaponprices as wp
                      --JOIN playerweapons as pw ON pw.class = wp.weapon 
                  --GROUP BY pw.id
              --) as wpn ON wpn.player = p.id
GROUP BY 
    p.nationality,
    p.nick,
    p.steamid64,
    p.cash,
    p.playtime,
    p.damage,
    p.destroyed,
    p.lastplayed
SELECT (IFNULL(LOG(1.5, cashearned),0) + IFNULL(LOG(1.3, roundswon), 0) +
        coalesce(an.cnt, 0)
       ) as rank,
       nationality, nick, steamid64, cash, playtime, damage, destroyed,
       (SELECT SUM(wp.price)
        FROM weaponprices wp JOIN
             playerweapons pw
             on pw.class = wp.weapons
        WHERE pw.id = pd.id
       ) as wepvalue,
       coalesce(an.cnt, 0) as achcount,
       lastplayed
FROM playerdata pd left outer join
     (SELECT id, count(*) as cnt
      FROM achievements_new an
      WHERE an.`value` = -1 
      GROUP BY an.id
     ) an
     on an.id = pd.id
ORDER BY rank DESC;
playerweapons(id, weapon);
weaponprices(class, price);
achievements_new(value, id);
SELECT
      ( COALESCE(LOG(1.5, pd.cashearned), 0)
      + COALESCE(LOG(1.3, pd.roundswon), 0)
      + COALESCE(an.cnt, 0))   AS rank
    , pd.nationality
    , pd.nick
    , pd.steamid64
    , pd.cash
    , pd.playtime
    , pd.damage
    , pd.destroyed
    , COALESCE(pw.wepvalue, 0) AS wepvalue
    , COALESCE(an.cnt, 0)      AS achcount
    , pd.lastplayed
FROM playerdata pd
      LEFT JOIN (
                  SELECT
                        id
                      , COUNT(*) AS cnt
                  FROM achievements_new
                  WHERE value = -1
                  GROUP BY
                        id
            ) an
                  ON pd.id = an.id
      LEFT JOIN (
                  SELECT
                        playerweapons.id
                      , SUM(price) AS wepvalue
                  FROM weaponprices
                        INNER JOIN playerweapons
                                    ON weaponprices.weapon = playerweapons.class
                  GROUP BY
                        playerweapons.id
            ) pw
                  ON pd.id = pw.id
ORDER BY
      rank DESC;