简体   繁体   中英

Optimizing MySQL query across multiple rows

my current query looks something like this. I've been trying to optimize it but I got no luck so far. My goal is to get the difference in stat_value between the current day and the previous day for every player and then order it. The current code works fine, but feels unoptimized to me. The ? values are filled in using Java.

SELECT t1.stat_value - 
       (SELECT stat_value 
          FROM leaderheadsplayersdata_daily t2 
         WHERE t2.player_id = t1.player_id 
           AND t2.day = ? 
           AND t2.stat_type = ? 
         LIMIT 1
       ) as sum
     , (SELECT name 
          FROM leaderheadsplayers 
         WHERE leaderheadsplayers.player_id = t1.player_id 
         LIMIT 1
       ) 
    FROM leaderheadsplayersdata_daily t1 
   WHERE day = ? 
     AND stat_type = ? 
   ORDER 
      BY sum DESC LIMIT 100

Table structure:

This is the main table containing the player id and username.

CREATE TABLE IF NOT EXISTS `leaderheadsplayers` 
(player_id INTEGER PRIMARY KEY AUTO_INCREMENT
,uuid VARCHAR(36) NOT NULL UNIQUE
,name VARCHAR(16) NOT NULL
,last_join DATETIME
) ENGINE = InnoDB

This is the table containing the daily data.

CREATE TABLE IF NOT EXISTS leaderheadsplayersdata_daily 
(player_id INTEGER NOT NULL
,stat_value DOUBLE NOT NULL
,stat_type VARCHAR(16) NOT NULL
,day INTEGER NOT NULL
,FOREIGN KEY (player_id) REFERENCES leaderheadsplayers(player_id) ON DELETE CASCADE
,PRIMARY KEY(player_id, stat_type, day)
) ENGINE = InnoDB

Thanks in advance

Because you only have 2 days, you can do a double join on the leaderheadsplayersdata_daily table.

It would look something like this:

SELECT
    p.player_id,
    p.name,
    (dc.stat_value-dp.statvalue) AS difference,
    dc.day,
FROM leaderheadsplayers p
JOIN leaderheadsplayersdata_daily dc ON p.player_id = dc.player_id
JOIN leaderheadsplayersdata_daily dp ON p.player_id = dp.player_id and dp.day = (dc.day-1)
WHERE dc.day = ?CURRENT_DAY?
ORDER BY difference DESC

dc stands for "date current". dp stands for "date previous". p stands for "player".

For good performance, add indexes on the columns player_id (in both tables) and day .

Sorry, I didn't test, have not ideea if I have syntax errors or stuff. Also, please replace ?CURRENT_DAY? with the actual day and add other conditions in WHERE clause, as needed

If ORDER BY difference DESC does not work, just do ORDER BY (dc.stat_value-dp.statvalue) DESC .

You have a lot of subqueries, you look like you could take a look at some documentation about JOINs . They're really useful.

Alternatively, you can try the following. Let me know how this version that uses implicit triple join fare with the one suggested above that uses explicit triple join. Thanks.

SELECT t3.player_id, improvement FROM 
   (SELECT t1.player_id as player_id, (t1.stat_value - t2.stat_value) as improvement 
      FROM leaderheadsplayersdata_daily t1 INNER JOIN leaderheadsplayersdata_daily t2 
         on t1.player_id = t2.player_id and t1.stat_type = t2.stat_type 
            and t2.day = ? and t1.day = ?) as t3 
   INNER JOIN leaderheadsplayers on 
      t3.player_id = leaderheadsplayers.player_id 
          ORDER BY improvement DESC LIMIT 100;

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