MySQL中锦标赛计分表的查询优化
Posted
技术标签:
【中文标题】MySQL中锦标赛计分表的查询优化【英文标题】:Query optimization for tournament scoring tables in MySQL 【发布时间】:2013-03-22 14:38:44 【问题描述】:我在锦标赛相关数据库中有两个表,我需要知道最优化的 SQL 查询以生成正确的整体结果。结果必须显示总得分,减去任何罚分,并且应根据首先达到该分数的人打破并列的分数。
在数据库表中,我有一个事件日志,其中每个分数都是随着球队进行比赛而添加的,我还有另一个表格,显示哪个球队是哪个锦标赛的一部分。
Table "xTournamentTeam" (connects a team to a tournament)
=======================
+-----+------------+--------+--------------+
| nID | Team Name | TeamID | TournamentID |
+-----+------------+--------+--------------+
| 1 | Team A | 12 | 25 |
| 2 | Team B | 13 | 25 |
| 3 | Team C | 14 | 25 |
| 4 | Team D | 15 | 25 |
| 3 | Team A | 12 | 32 |
| 4 | Team B | 13 | 32 |
+-----+------------+--------+--------------+
Table "nEventLog" (records scoring during a tournament)
=================
+-----+---------------+---------+----------+----------------+-----------------------+
| nID | nTournamentID | nTeamID | nPoints | nPointsPenalty | nEventTime |
+-----+---------------+---------+----------+----------------|-----------------------+
| 1 | 25 | 15 | 100 | 0 | 1/24/2013 6:05:14 AM |
| 2 | 25 | 14 | 100 | 0 | 1/24/2013 6:29:55 AM |
| 3 | 25 | 14 | 100 | 25 | 1/24/2013 7:09:34 AM |
| 4 | 25 | 12 | 100 | 0 | 1/24/2013 7:12:28 AM |
| 5 | 25 | 12 | 100 | 0 | 1/24/2013 8:42:59 AM |
| 6 | 25 | 12 | 100 | 50 | 1/24/2013 8:43:36 AM |
| 7 | 25 | 14 | 100 | 0 | 1/24/2013 9:15:24 AM |
| 8 | 25 | 15 | 100 | 0 | 1/24/2013 9:15:27 AM |
| 9 | 32 | 12 | 100 | 0 | 1/28/2013 8:33:49 AM |
| 10 | 32 | 13 | 100 | 25 | 1/28/2013 2:15:12 PM |
| 11 | 32 | 12 | 100 | 10 | 1/28/2013 7:12:25 AM |
| 12 | 32 | 13 | 100 | 0 | 1/29/2013 7:18:06 AM |
+-----+---------------+---------+----------+----------------+-----------------------+
在上述数据的情况下,我需要的查询应该为锦标赛 #25 生成以下结果:
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| nRank | Team Name | TeamID | TournamentID | nTotalPoints | nTotalPointsPenalty | nLatestEventTime |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| 1 | Team A | 12 | 25 | 300 | 50 | 1/24/2013 8:43:36 AM |
| 2 | Team C | 14 | 25 | 300 | 25 | 1/24/2013 9:15:24 AM |
| 3 | Team D | 15 | 25 | 200 | 0 | 1/24/2013 9:15:27 AM |
| 4 | Team B | 13 | 25 | 0 | 0 | |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
出于加载目的,我试图不惜一切代价避免子查询,因为最终查询应尽可能优化。 “nRank”列可以通过编程方式生成...... mysql 不应该返回它,但我将它作为参考。
我最接近的查询是这个,但它没有返回“Team B”,因为他们在“nEventLog”表中没有任何记录 nTournamentID #25:
SELECT xTournamentTeam.nTeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.nTeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.nTournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.nTeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.nTournamentID = 33
AND nEventLog.nTournamentID = 33
GROUP BY
xTournamentTeam.nID
, xTournamentTeam.nTournamentID
ORDER BY
nTotalPoints DESC
, nLatestEventTime DESC
我当然不是 MySQL 查询方面的专家,而且我已经为此工作了两天,但没有取得多大成功,因此我们将不胜感激。
【问题讨论】:
您是否在您的select
语句上运行了 explain
?
“出于加载目的,我试图不惜一切代价避免子查询,因为最终查询应尽可能优化。”是什么意思?你能记录下为什么不优化子查询吗?这与我对 MySQL 和一般 SQL 优化器的了解背道而驰。
@GordonLinoff 我想我已经看到了几篇反对使用子查询朝那个方向发展的帖子。据我所知,对于可以通过子查询完成的事情,他们对服务器施加了太大的压力。我对他们没有任何反对意见,但我确实非常需要最优化的查询。目前,我正在使用多个查询和 php 执行上述操作,并且在锦标赛期间服务器上的负载(有数千人访问统计页面并不断刷新)非常糟糕,因此优化是关键。
@迈克尔。 . .几乎所有 SQL 引擎的执行引擎对子查询一无所知。他们正在执行数据流操作。子查询是语法约定。它们可能会也可能不会针对给定的引擎进行优化,但大多数 SQL 结构都是如此。
@Daedalus 因为我不是专家,所以 EXPLAIN 的结果并不能告诉我太多,但它们在这里:
【参考方案1】:
我稍微改变一下你的逻辑,我认为它起作用了:
SELECT
xTournamentTeam.TeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.TeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.TournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.TournamentID = nEventLog.nTournamentID AND xTournamentTeam.TeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.TournamentID = 25
GROUP BY
xTournamentTeam.TeamID
, xTournamentTeam.TournamentID
, xTournamentTeam.TeamName
ORDER BY
nTotalPoints DESC
如果需要,可以将空值格式化为 0 或其他值。
【讨论】:
我现在正在对其进行一些测试,但到目前为止它看起来正在运行。 :) 只做了一处改动:“ORDER BY nTotalPoints DESC, nLatestEventTime”。在决胜局的情况下,这可以确保首先获得分数的球队获得领先。否则,您的 SQL 查询将完美运行!感谢您的帮助...您添加的“LEFT OUTER JOIN”语句很巧妙!以上是关于MySQL中锦标赛计分表的查询优化的主要内容,如果未能解决你的问题,请参考以下文章