在WHERE子句中使用子查询进行MYSQL UPDATE查询 - 优化

时间:2013-07-02 18:23:09

标签: mysql sql-update subquery query-optimization

我正在开发一个需要硬编码排名的项目(请不要进行标准化评论)。该示例有一个分数表。每个得分记录涉及一个人和游戏的特定迭代。我们只想对一个人对游戏的特定迭代的最高分进行排名,因为一个人可以在某个时刻打破他们自己的分数并拥有多个记录。以下查询用于标记特定游戏迭代的每个人的最高分数,以便可以单独排名。

以下是非常缓慢的,我想加快速度:

/* Define a game iteration */
SET @VarID=(can be any number from 1-200k);

/* WITHIN A game iteration RESET ALL OF THE PERSONAL BEST */

UPDATE scores m
SET m.personal_best='0'
WHERE VarID = @VarID;

/* IDENTIFY THE "BEST" (in this case the highest score per PeopleID) */

UPDATE scores m
SET m.personal_best='1'
WHERE m.ScoreID IN 
(
    SELECT _scoreID
    FROM
    (   
        SELECT ScoreID as _scoreID FROM scores WHERE VarID = @VarID AND NewScore = ( select max(NewScore) from scores i where i.PeopleID = scores.PeopleID AND VarID = @VarID ) ORDER BY VarID, NewScore DESC   
    ) s

) AND VarID = @VarID;

1 个答案:

答案 0 :(得分:0)

您可以使用MySQL的多表UPDATE语法在没有子查询的情况下执行此操作。

使用OUTER JOIN,查找同一个人和varid的分数,以及更高的分数。如果未找到更高的分数(即,如果 m 是得分最高的行),则外连接将使连接表的所有列为NULL。

UPDATE scores m
LEFT OUTER JOIN scores AS better
  ON m.VarID = better.VarID AND m.PeopleID = better.PeopleID 
  AND m.NewScore < better.NewScore
SET m.personal_best='1'
WHERE VarID = @VarID
  AND better.VarID IS NULL;

但可能存在关系;如果该人不止一次达到最佳分数,则会将多行标记为最佳分数。如果你想避免这种情况,你必须使用其他保证唯一的列来打破关系:

UPDATE scores m
LEFT OUTER JOIN scores AS better
  ON m.VarID = better.VarID AND m.PeopleID = better.PeopleID 
  AND (m.NewScore < better.NewScore OR m.NewScore = better.NewScore AND m.ScoreID < better.ScoreID)
SET m.personal_best='1'
WHERE VarID = @VarID
  AND better.VarID IS NULL;