我正在用SQL编写一个查询来提取35岁赛季的球员本垒打总数,他们在职业生涯中已经打了500多个本垒打。
SELECT b.playerID, b.yearID, b.HR
FROM batting b
JOIN master m ON m.playerID = b.playerID
WHERE b.yearID - m.birthYear = '35'
HAVING SUM(b.HR) > 500
此查询在执行时超时。我已成功创建一个查询,以返回特定年龄段的玩家本垒打总数。我还成功地创建了一个查询,以返回500家本垒打俱乐部的球员。
当我尝试将它们结合起来时,某些事情会让它超时,我无法确定原因。
这是一个效果很好的查询:
SELECT b.playerID, b.yearID, b.HR
FROM batting b
JOIN MASTER M ON b.playerID = m.playerID
WHERE b.yearID - m.birthYear = 35 AND b.yearID = 2015
ORDER BY b.HR DESC
现在如果我只能归还那些在这个结果中击中500个职业本垒打的球员。 2015年仅有500名本垒打击球手。
答案 0 :(得分:0)
最可能的解释是优化程序选择的执行计划效率不高。
我们没有看到的是这些表格中可用的索引。
关于查询突出的一点是:
WHERE b.yearID - m.birthYear = '35'
MySQL将使用给定的player_id从master
获取每一行,并将其与batting
中每一行匹配相同的player_id(由于等式连接谓词)
ON m.playerID = b.playerID
然后MySQL必须采用那组合并的行,然后计算这个表达式
b.yearID - m.birthYear
然后从中获取结果并将其与'35'进行比较。
假设playerID
列上的master
列是唯一的
我们希望看到以可以利用batting
上具有(playerID,yearID)
前导列的索引的形式编写的查询谓词。
SELECT b.playerid
, b.yearid
, SUM(b.hr) AS hr
FROM master m
JOIN batting b
ON b.playerid = m.playerid
AND b.yearid = m.birthyear + 35
GROUP BY b.playerid, b.yearid
HAVING SUM(b.hr) > 500
ORDER BY SUM(b.hr) DESC
要为每个玩家返回行,您需要一个GROUP BY
子句。要获得总的本垒打,您将需要SELECT列表中的SUM()聚合。
为了获得最佳的查询效果,您需要覆盖索引
... ON batting (playerid, yearid, hr)
如果playerid
在master
表上不唯一,则查询不会保证您对SUM(b.hr)的期望值,该值可能是double,triple等预期的是什么。
使用EXPLAIN查看执行计划。
还要注意可能对执行计划产生负面影响的隐式数据类型转换。我们假设两个表中playerid
列的数据类型匹配,yearid
和birthyear
列的数据类型是数字。
修改强>
我原来的答案主要集中在你的查询“超时”的原因上,而我错过了你想要达到的结果的规范:
返回 职业 人力资源总数超过500的玩家,并返回 年 总人力资源每个球员的年份。
(我将讨论适当确定玩家年满35岁的“年份”,并使用原始查询中的标准。)
一种方法是使用条件聚合。使用在条件为TRUE时返回HR的表达式,否则返回0或NULL。然后将该表达式包装在SELECT列表中的SUM聚合中。
如果我们想为职业人力资源总数超过500且在指定年份batting
至少有一行的玩家返回仅行...
SELECT b.playerid
, MAX(IF(b.yearid = m.birthyear + 35,b.yearid,NULL)) AS yearid
, SUM(IF(b.yearid = m.birthyear + 35, b.hr, 0)) AS year_hr
FROM master m
JOIN batting b
ON b.playerid = m.playerid
GROUP BY b.playerid
HAVING SUM(b.hr) > 500
AND MAX(IF(b.yearid = m.birthyear + 35,b.yearid,NULL)) IS NOT NULL
ORDER BY ...
要为每个职业人力资源总数超过500的玩家返回行数,即使指定batting
的{{1}}中没有行,我们也可以调整查询以省略第二个条件HAVING子句,并在SELECT列表中使用表达式m.birthyear + 35
yearid
请注意,职业人力资源总数恰好为500的玩家将被排除在外。