2

我不是 MySQL 专家,因为它可能从下面的查询中显示,但我设法让我的查询给我想要的结果,但对我来说似乎很慢:

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大约有 11,570 行,boxers大约有 86,370 行,目前运行时间在 0.6500 - 0.7500 秒之间。我在 and 上有一个主键,在boxers.idand上有一个bouts.bout_id索引bouts.boxer_1bouts.boxer_2但是我对使用索引的了解也不是很好。

查询这么慢是否正常,我能做些什么来帮助加快速度吗?

更新

解释查询结果。如果这不正确,你必须让我知道...

MySQL解释输出

更新 2

回合表结构:

在此处输入图像描述

Boxer 表结构:

在此处输入图像描述

更新 3

好吧,也许有些进展...

如果我改变

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

至:

LEFT JOIN bouts opp_bouts ON (opp_bouts.boxer_1=opponent.id) AND opp_bouts.bout_date < bouts.bout_date

它将查询速度提高到 0.0250 左右,这似乎是一个很大的速度问题。我可以改进 OR 功能还是以不同的方式来做?

更新 4

多亏了 Kickstart,我现在有了下面的代码,它的速度要快得多,但我不是 100% 我已经正确地完成了所有事情......或者我是否应该在某些列上建立索引以进一步加快速度?我不确定它会如何扩大规模,但它可能是我能得到的最好的?

bouts现在有 ~46,066 行和boxers~90,531,查询在 0.0466 处运行,索引在 bout_date 和 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
4

2 回答 2

6

使用 IF 来决定几乎所有的列是指第一个还是第二个拳击手可能会减慢速度。

可能最好有 2 个子选择(boxer_1 和 boxer_2 各一个),将结果合并在一起,然后将结果合并到 SUM 和 COUNT。

编辑。简要示例(不完整,因为我不完全了解所有数据的来源)。将 4 个查询联合在一起(每个 boxer_1 和 boxer_2 在回合中各有一个,对于回合中第二次加入的那些又各一个)。使用此联合查询的结果进行实际计算。

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

这样,您可以在子选择中获得所需的值,而不是在各种聚合函数上使用 IF 语句

于 2013-05-23T13:04:02.143 回答
0

为了提高 SQL 查询的速度,您可以使用临时表进行左连接,然后在所有选择总和之后,如果

创建临时表 new_temp_table as select * from Your query

之后 :

从 new_temp_table 中选择(所有您的选择代码)

当您使用临时表时,这对您的情况很有帮助,不要一次进行查询,而是在 2 次或更长时间内进行查询,这可以提高执行时间。2-3 查询更简单比 1 查询 3 时间复杂更快。连接 SQL 关闭后,临时表被丢弃

示例(法语):临时表 SQL

于 2013-06-07T01:22:24.473 回答