Robin De Baets Robin De Baets - 4 months ago 7
MySQL Question

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

Answer

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.

Comments