I'm no MySQL expert as it probably shows from my query below, but I've managed to get my query to give me the results i want, but it seems very slow to me:
SELECT
bouts.bout_id,
bouts.bout_date,
bouts.winner,
bouts.result,
bouts.ended_in_round,
bouts.total_rounds,
bouts.verified AS verified,
CONCAT(opponent.first_name, ' ', opponent.last_name) AS opponent_name,
opponent.last_name AS opponent_lastname,
opponent.id AS opponent_id,
IF(opponent.id = bouts.boxer_1, bouts.boxer_1_weight, bouts.boxer_2_weight) AS opp_weight,
IF(opponent.id = bouts.boxer_1, bouts.boxer_2_weight, bouts.boxer_1_weight) AS fighter_weight,
SUM(opp_bouts.ended_in_round) AS opp_total_rounds_boxed,
SUM(IF(opp_bouts.winner = -1,1,0)) AS opp_draws,
SUM(IF(opp_bouts.winner = opponent.id,1,0)) AS opp_wins,
COUNT(opp_bouts.bout_id) AS opp_fights,
IF(opponent.id = bouts.boxer_1, bouts.bxr2_power_points, bouts.bxr1_power_points) AS boxer_power,
IF(opponent.id = bouts.boxer_1, bouts.bxr2_chin_points, bouts.bxr1_chin_points) AS boxer_chin,
IF(opponent.id = bouts.boxer_1, bouts.bxr2_boxer_points, bouts.bxr1_boxer_points) AS boxer_boxer,
SUM(IF(opponent.id = opp_bouts.boxer_1, opp_bouts.bxr1_power_points, opp_bouts.bxr2_power_points)) AS opp_power,
SUM(IF(opponent.id = opp_bouts.boxer_1, opp_bouts.bxr1_chin_points, opp_bouts.bxr2_chin_points)) AS opp_chin,
SUM(IF(opponent.id = opp_bouts.boxer_1, opp_bouts.bxr1_boxer_points, opp_bouts.bxr2_boxer_points)) AS opp_boxer,
SUM(IF(opponent.id = opp_bouts.boxer_1, opp_bouts.bxr1_exp_points, opp_bouts.bxr2_exp_points)) AS opp_experience,
MAX(IF(opp_bouts.verified = 1, opp_bouts.bout_date, 0)) AS verified_up_to,
MAX(opp_bouts.bout_date) AS opp_last_bout
FROM
bouts
LEFT JOIN boxers opponent ON opponent.id=IF(bouts.boxer_2 = '" . $boxer_id . "', bouts.boxer_1, bouts.boxer_2)
LEFT JOIN bouts opp_bouts ON (opp_bouts.boxer_1=opponent.id OR opp_bouts.boxer_2=opponent.id) AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < '" . $to_date . "' AND (bouts.boxer_1 = '" . $boxer_id . "' OR bouts.boxer_2 = '" . $boxer_id . "')
GROUP BY bouts.bout_id
ORDER BY bouts.bout_date DESC
bouts
has around 11,570 rows, boxers
has around 86,370 rows, and it's currently taking between 0.6500 - 0.7500 seconds to run. I have a primary key on boxers.id
and bouts.bout_id
, and indexes on bouts.boxer_1
and bouts.boxer_2
, but my knowledge of using indexes isn't too good either.
Is it normal for the query to be this slow, and is there anything i can do to help speed it up a little?
UPDATE
Explain result of the query. You'll have to let me know if this isn't correct...
UPDATE 2
Bout table structure:
Boxer table structure:
UPDATE 3
Ok, some progress maybe...
If i change
LEFT JOIN bouts opp_bouts ON (opp_bouts.boxer_1=opponent.id OR opp_bouts.boxer_2=opponent.id) AND opp_bouts.bout_date < bouts.bout_date
to:
LEFT JOIN bouts opp_bouts ON (opp_bouts.boxer_1=opponent.id) AND opp_bouts.bout_date < bouts.bout_date
It speeds the query up to around 0.0250, and this seems to be a big speed issue. Could i improve the OR function or do it in a different way maybe?
UPDATE 4
Thanks to Kickstart i now have the below code which is soo much faster but I'm not 100% I've done everything correctly... or if i should have indexes on some columns to speed it up further? I'm not sure how it'll scale up yet wither, but it might be the best I'll get?
bouts
now has ~46,066 rows and boxers
~90,531, the query runs at 0.0466 with index on bout_date and both boxer_1/2.
SELECT bout_id,
bout_date,
winner,
result,
ended_in_round,
total_rounds,
verified,
opponent_first_name,
opponent_last_name,
opponent_id,
opp_weight,
fighter_weight,
SUM(opp_ended_in_round) AS opp_total_rounds_boxed,
SUM(IF(opp_winner = -1,1,0)) AS opp_draws,
SUM(IF(opp_winner = opponent_id,1,0)) AS opp_wins,
COUNT(opp_id) AS opp_fights,
boxer_power,
boxer_chin,
boxer_boxer,
SUM(opp_power_rating) AS opp_power,
SUM(opp_chin_rating) AS opp_chin,
SUM(opp_boxer_rating) AS opp_boxer,
SUM(opp_exp_rating) AS opp_experience,
MIN(IF(opp_verified = 1,9999-01-01 , opp_bout_date)) AS verified_up_to,
MAX(opp_bout_date) AS opp_last_bout
FROM (
SELECT bouts.bout_id, bouts.total_rounds, bouts.result, bouts.verified, opp_bouts.verified AS opp_verified, opp_bouts.bout_id AS opp_id, bouts.winner, opp_bouts.winner AS opp_winner, bouts.ended_in_round, opp_bouts.ended_in_round AS opp_ended_in_round, bouts.boxer_2_weight AS opp_weight, bouts.bxr1_power_points AS boxer_power, opp_bouts.bxr1_power_points AS opp_power_rating , opp_bouts.bxr1_chin_points AS opp_chin_rating, opp_bouts.bxr1_boxer_points AS opp_boxer_rating, opp_bouts.bxr1_exp_points AS opp_exp_rating, bouts.bxr1_chin_points AS boxer_chin, bouts.bxr1_boxer_points AS boxer_boxer, bouts.boxer_1_weight AS fighter_weight, bouts.boxer_2 AS opponent_id, bouts.bout_date, opp_bouts.bout_date AS opp_bout_date, opponent.first_name AS opponent_first_name, opponent.last_name AS opponent_last_name
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = boxer_2
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_1 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < 'NOW()'
AND bouts.boxer_1 = '63514'
UNION ALL
SELECT bouts.bout_id, bouts.total_rounds, bouts.result, bouts.verified, opp_bouts.verified AS opp_verified, opp_bouts.bout_id AS opp_id, bouts.winner, opp_bouts.winner AS opp_winner, bouts.ended_in_round, opp_bouts.ended_in_round AS opp_ended_in_round, bouts.boxer_2_weight AS opp_weight, bouts.bxr1_power_points AS boxer_power, opp_bouts.bxr2_power_points AS opp_power_rating, opp_bouts.bxr2_chin_points AS opp_chin_rating, opp_bouts.bxr2_boxer_points AS opp_boxer_rating, opp_bouts.bxr2_exp_points AS opp_exp_rating, bouts.bxr1_chin_points AS boxer_chin, bouts.bxr1_boxer_points AS boxer_boxer, bouts.boxer_1_weight AS fighter_weight, bouts.boxer_2 AS opponent_id, bouts.bout_date, opp_bouts.bout_date AS opp_bout_date, opponent.first_name AS opponent_first_name, opponent.last_name AS opponent_last_name
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = boxer_2
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_2 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < 'NOW()'
AND bouts.boxer_1 = '63514'
UNION ALL
SELECT bouts.bout_id, bouts.total_rounds, bouts.result, bouts.verified, opp_bouts.verified AS opp_verified, opp_bouts.bout_id AS opp_id, bouts.winner, opp_bouts.winner AS opp_winner, bouts.ended_in_round, opp_bouts.ended_in_round AS opp_ended_in_round, bouts.boxer_1_weight AS opp_weight, bouts.bxr2_power_points AS boxer_power, opp_bouts.bxr1_power_points AS opp_power_rating, opp_bouts.bxr1_chin_points AS opp_chin_rating, opp_bouts.bxr1_boxer_points AS opp_boxer_rating, opp_bouts.bxr1_exp_points AS opp_exp_rating, bouts.bxr2_chin_points AS boxer_chin, bouts.bxr2_boxer_points AS boxer_boxer, bouts.boxer_2_weight AS fighter_weight, bouts.boxer_1 AS opponent_id, bouts.bout_date, opp_bouts.bout_date AS opp_bout_date, opponent.first_name AS opponent_first_name, opponent.last_name AS opponent_last_name
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = boxer_1
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_1 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < 'NOW()'
AND bouts.boxer_2 = '63514'
UNION ALL
SELECT bouts.bout_id, bouts.total_rounds, bouts.result, bouts.verified, opp_bouts.verified AS opp_verified, opp_bouts.bout_id AS opp_id, bouts.winner, opp_bouts.winner AS opp_winner, bouts.ended_in_round, opp_bouts.ended_in_round AS opp_ended_in_round, bouts.boxer_1_weight AS opp_weight, bouts.bxr2_power_points AS boxer_power, opp_bouts.bxr2_power_points AS opp_power_rating, opp_bouts.bxr2_chin_points AS opp_chin_rating, opp_bouts.bxr2_boxer_points AS opp_boxer_rating, opp_bouts.bxr2_exp_points AS opp_exp_rating, bouts.bxr2_chin_points AS boxer_chin, bouts.bxr2_boxer_points AS boxer_boxer, bouts.boxer_2_weight AS fighter_weight, bouts.boxer_1 AS opponent_id, bouts.bout_date, opp_bouts.bout_date AS opp_bout_date, opponent.first_name AS opponent_first_name, opponent.last_name AS opponent_last_name
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = boxer_1
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_2 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < 'NOW()'
AND bouts.boxer_2 = '63514'
) AS my_table GROUP BY bout_id ORDER BY bout_date DESC
Using IF to decide on just about all the columns whether you are referring to the first or 2nd boxer will likely slow things down.
Possibly best to have 2 subselects (one for each of boxer_1 and boxer_2), union the results together and then to the SUMs and COUNTs on the results of that.
EDIT. Brief example (not full as I don't fully understand where all the data is coming from). Have 4 queries unioned together (1 for each of boxer_1 and boxer_2 on bouts, and again one of each for those on the 2nd join on bouts). Use the results of this unioned query to do you actual calculations.
SELECT SomeFields,
SUM(SomeField),
etc
FROM
(
SELECT bouts.boxer_1 AS boxer, bouts.boxer_2 AS opponent, opp_bouts.boxer_2 AS opponentsPrevOpponent
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = bouts.boxer_2
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_1 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < '" . $to_date . "'
AND bouts.boxer_1 = '" . $boxer_id . "'
UNION ALL
SELECT bouts.boxer_1 AS boxer, bouts.boxer_2 AS opponent, opp_bouts.boxer_1 AS opponentsPrevOpponent
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = bouts.boxer_2
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_2 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < '" . $to_date . "'
AND bouts.boxer_1 = '" . $boxer_id . "'
UNION ALL
SELECT bouts.boxer_2 AS boxer, bouts.boxer_1 AS opponent, opp_bouts.boxer_2 AS opponentsPrevOpponent
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = bouts.boxer_1
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_1 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < '" . $to_date . "'
AND bouts.boxer_2 = '" . $boxer_id . "'
UNION ALL
SELECT bouts.boxer_2 AS boxer, bouts.boxer_1 AS opponent, opp_bouts.boxer_1 AS opponentsPrevOpponent
FROM bouts
LEFT JOIN boxers opponent ON opponent.id = bouts.boxer_1
LEFT JOIN bouts opp_bouts ON opp_bouts.boxer_2 = opponent.id AND opp_bouts.bout_date < bouts.bout_date
WHERE bouts.bout_date < '" . $to_date . "'
AND bouts.boxer_2 = '" . $boxer_id . "'
) Sub1
This way you can get the values you need in the subselects rather than using IF statements on the various aggregate functions
For add speed to your SQL query you may use temporary table to do your left join and after to all your select sum and if
create temporary table new_temp_table as select * from Your query
and after :
select (all your select code) from new_temp_table
When you use temporary table this can be helpfull in your case, not do your query in one time but in 2 or more time this can improve the time execution. 2-3 query more simple is faster thant 1 quesry 3 time complexe. After the connection SQL close the temporary table is drop
Example (in french): table temporaire SQL
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.