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

boutsboxers11,570 行あり、約 86,370 行あり、現在、実行に 0.6500 ~ 0.7500 秒かかります。と に主キーがboxers.idありbouts.bout_id、 と にインデックスがありますbouts.boxer_1bouts.boxer_2、インデックスの使用に関する知識もあまりありません。

クエリがこれほど遅いのは普通のことですか?少しスピードアップするためにできることはありますか?

アップデート

クエリの結果を説明します。これが正しくない場合は、私に知らせなければなりません...

MySQL Explain の出力

更新 2

試合テーブルの構造:

ここに画像の説明を入力

ボクサーのテーブル構造:

ここに画像の説明を入力

更新 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 行と最大 90,531 行がありboxers、クエリは bout_date と両方の boxer_1/2 のインデックスで 0.0466 で実行されます。

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 番目のボクサーのどちらを参照しているかをほぼすべての列で判断すると、処理が遅くなる可能性があります。

おそらく、2 つのサブセレクト (boxer_1 と boxer_2 のそれぞれに 1 つ) を用意し、結果を結合してから、その結果の SUM と COUNT にします。

編集。簡単な例 (すべてのデータがどこから来ているのか完全には理解していないため、完全ではありません)。4 つのクエリを結合します (試合の boxer_1 と boxer_2 のそれぞれに 1 つずつ、試合の 2 番目の結合にそれぞれ 1 つずつ)。このユニオン クエリの結果を使用して、実際の計算を行います。

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クエリを高速化するために、一時テーブルを使用して左結合を実行し、その後すべての選択合計を実行することができます。

select * from Your query として一時テーブル new_temp_table を作成します

以降 :

select (すべての選択コード) from new_temp_table

一時テーブルを使用する場合、これはあなたの場合に役立ちます.1回でクエリを実行するのではなく、2回以上実行すると実行時間が改善されます. 2 ~ 3 クエリの単純なほうが、1 クエリ 3 回の複雑なクエリよりも高速です。接続 SQL を閉じた後、一時テーブルは削除されます

例 (フランス語): table temporaire SQL

于 2013-06-07T01:22:24.473 に答える