大家好,并提前致谢
我有表accounts
,votes
和contests
投票由作者ID,胜利者ID和比赛ID组成,以阻止人们投票两次
我喜欢为任何特定帐户显示,他们赢了多少次比赛,他们获得了多少次第二次以及他们获得了多少次第三次
什么是最快(执行时间)的方式来做到这一点? (我正在使用MySQL)
答案 0 :(得分:1)
在使用MySQL很长一段时间后,我得出的结论是,几乎任何GROUP BY的使用对性能都非常不利,所以这里有一个带有几个临时表的解决方案。
CREATE TEMPORARY TABLE VoteCounts (
accountid INT,
contestid INT,
votecount INT DEFAULT 0
);
INSERT INTO VoteCounts (accountid, contestid)
SELECT DISTINCT v2.accountid, v2.contestid
FROM votes v1 JOIN votes v2 USING (contestid)
WHERE v1.accountid = ?; -- the given account
确保您在votes(accountid, contestid)
上有索引。
现在,您有一个表格,其中列出了您的指定用户所参加的所有比赛,以及所有其他参加同一比赛的比赛。
UPDATE Votes AS v JOIN VoteCounts AS vc USING (accountid, contestid)
SET vc.votecount = vc.votecount+1;
现在,每个比赛的每个帐户都有投票数。
CREATE TEMPORARY TABLE Placings (
accountid INT,
contestid INT,
placing INT
);
SET @prevcontest := 0;
SET @placing := 0;
INSERT INTO Placings (accountid, placing, contestid)
SELECT accountid,
IF(contestid=@prevcontest, @placing:=@placing+1, @placing:=1) AS placing,
@prevcontest:=contestid AS contestid
FROM VoteCounts
ORDER BY contestid, votecount DESC;
现在,您有一张桌子,每个帐户与每个比赛中各自的位置配对。获得给定位置的计数很容易:
SELECT accountid, COUNT(*) AS count_first_place
FROM Placings
WHERE accountid = ? AND placing = 1;
你可以使用MySQL技巧在一个查询中完成所有三个操作。布尔表达式总是在MySQL中返回一个整数值0或1,因此您可以使用SUM()
来计算1的值。
SELECT accountid,
SUM(placing=1) AS count_first_place,
SUM(placing=2) AS count_second_place,
SUM(placing=3) AS count_third_place
FROM Placings
WHERE accountid = ?; -- the given account
重新评论:
是的,无论从标准化数据到您想要的结果,这都是一项复杂的任务。您希望它再次聚合(求和),排名和聚合(计数)。这是一堆工作! : - )
此外,单个查询并不总是执行给定任务的最快方法。程序员常常误解,较短的代码隐含着更快的代码。
注意我没有对此进行测试,因此您的里程可能会有所不同。
重新提出有关更新的问题:
在不使用GROUP BY的情况下,每个帐户获得COUNT()
个投票是一种棘手的方法。我已经添加了表别名v和vc,所以现在可能会更清楚了。在votes
表中,给定帐户/竞赛有N行。在votescount
表格中,每个帐户/竞赛都有一行。当我加入时,UPDATE将根据N行进行评估,因此如果我为这N行中的每一行添加1,我会在与votescount
相对应的每个相应帐户/竞赛的行中得到N的计数。< / p>
答案 1 :(得分:0)
如果我正确地解释事情,要阻止人们投票两次,我认为你只需要作者(账户?)ID和contestID在投票表上有一个唯一索引。它不会阻止人们拥有多个帐户并进行两次投票,但这会阻止任何人在同一帐户中两次投票。为了防止欺诈(袜子傀儡帐户),您需要检查投票模式,并检测帐户何时更频繁地为另一个帐户投票,然后才能进行统计。除非你有很多可能真的很难的比赛。