WHERE 子句中带有子查询的 MYSQL UPDATE 查询 - 优化

Posted

技术标签:

【中文标题】WHERE 子句中带有子查询的 MYSQL UPDATE 查询 - 优化【英文标题】:MYSQL UPDATE query with subquery in the WHERE clause - optimization 【发布时间】:2013-07-02 18:23:09 【问题描述】:

我正在从事一个需要硬编码排名的项目(请不要标准化 cmets)。该示例有一个分数表。每条得分记录都与一个人和一个特定的游戏迭代有关。我们只想对一个人在游戏的特定迭代中的最高得分进行排名,因为一个人可能在某个时候打破自己的得分并拥有多个记录。以下查询用于标记每个人在特定游戏迭代中的最高分数,以便可以单独对其进行排名。

以下内容非常慢,我想加快速度:

/* 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】:

您可以使用 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;

【讨论】:

以上是关于WHERE 子句中带有子查询的 MYSQL UPDATE 查询 - 优化的主要内容,如果未能解决你的问题,请参考以下文章

列子句中带有子查询的 MS SQL Server 数据透视表

Laravel 5.8,在 where 子句中带有 Count(*) 的棘手子查询

IF 语句中带有子查询的 MySQL SELECT 语句的语法

Hive 中带有 Join 或 Where 子句的条件

where 子句中带有字符的整数字段返回奇怪的输出

SQL Server 中带条件的 Where 子句