优化MySQL查询,选择中选择,相同的多个
我需要帮助优化我创建的MySQL语句。它正是我想要的,但是我有一种很好的感觉,它会非常慢,因为我在语句中进行了多次选择,并且我还多次查询新的。这是我第一次做这样的重要陈述,我习惯了简单的从哪里选择风格垃圾 我可能会做一些解释,这是一个排行榜风格的东西为我的网站 -第一个变量输出是根据所示公式计算的排名,Log+Log+成就 -Wepvalue是该id拥有的武器值的总和。playerweapons包含所有武器,武器价格将类型转换为价格,然后总和计算值 -Achcount只是解锁的成就数量。也许这可以通过排名输出进行优化 -成就中的id\u new和playerweapons是playerdata中id的外键 表结构: 玩家数据: 新成就: 武器价格:优化MySQL查询,选择中选择,相同的多个,mysql,sql,optimization,Mysql,Sql,Optimization,我需要帮助优化我创建的MySQL语句。它正是我想要的,但是我有一种很好的感觉,它会非常慢,因为我在语句中进行了多次选择,并且我还多次查询新的。这是我第一次做这样的重要陈述,我习惯了简单的从哪里选择风格垃圾 我可能会做一些解释,这是一个排行榜风格的东西为我的网站 -第一个变量输出是根据所示公式计算的排名,Log+Log+成就 -Wepvalue是该id拥有的武器值的总和。playerweapons包含所有武器,武器价格将类型转换为价格,然后总和计算值 -Achcount只是解锁的成就数量。也许这可
提前谢谢 试试下面的查询。 我使用左连接而不是连接,因为可能有没有成就或武器的球员。如果你不需要这些球员,你可以使用加入
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;