简体   繁体   中英

MYSQL UPDATE query with subquery in the WHERE clause - optimization

I am working on a project where hardcoding rankings is necessary (no normalization comments please). The example has a table of scores. Each score record relates to a person and to a specific iteration of a game. We are only wanting to rank the highest score a person has for that specific iteration of a game since a person can at some point break their own score and have multiple records. The following query is being used to mark each persons highest score for the specific game iteration, so that it can be ranked separately.

The following is extremely slow and i want to speed it up:

/* 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;

You can do this without subqueries, using MySQL's multi-table UPDATE syntax.

Use an OUTER JOIN, looking for scores for the same person and varid, and a higher score. If no higher score is found (ie if m is the row with the highest score), then the outer join will make all columns of the joined table 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;

But there could be ties; if the person achieves their best score more than once, more than one row will be marked as their best score. If you want to avoid this, you must break the ties using some other column that is guaranteed to be unique:

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM