1

このクエリがあります

  SELECT  
   shot.hole AS hole,
   shot.id AS id,
   (SELECT s.id FROM shot AS s 
      WHERE s.hole = shot.hole AND s.shot_number > shot.shot_number AND shot.round_id = s.round_id 
       ORDER BY s.shot_number ASC LIMIT 1) AS next_shot_id,
   shot.distance AS distance_remaining,
   shot.type AS hit_type,
   shot.area AS onto
  FROM shot 
  JOIN course ON shot.course_id = course.id
  JOIN round ON shot.round_id = round.id
  WHERE round.uID = 78

これにより、約 0.7 秒で 900~ 行が返されます。これは問題ありませんが、このような行がさらに必要です

(SELECT s.id FROM shot AS s 
 WHERE s.hole = shot.hole AND s.shot_number > shot.shot_number AND shot.round_id = s.round_id 
 ORDER BY s.shot_number ASC LIMIT 1) AS next_shot_id,

例えば

   (SELECT s.id FROM shot AS s 
    WHERE s.hole = shot.hole AND s.shot_number < shot.shot_number AND shot.round_id = s.round_id 
    ORDER BY s.shot_number ASC LIMIT 1) AS past_shot_id,

これを追加すると、ロード時間が数十秒に長くなり、ページがまったくロードされないか、MySQL がロックアップしshow processlistて、クエリがそこにあることが示されますsending data

これらのサブクエリで句を削除するORDER BY s.shot_number ASCと、クエリ時間が 0.05 秒に短縮され、はるかに改善されます。ただし、ORDER BY古いランダムな行ではなく、次または過去の行 (ショット) が返されるようにするために必要です。

このクエリを改善して、実行速度を上げて同じ結果を返すにはどうすればよいですか。おそらく、次の行と過去の行を取得するための私のアプローチは最適ではなく、次の行 ID と前の行 ID を返す別の方法を検討する必要がありますか?

編集 - 追加の背景情報

私のテスト用ドメインであるサブドメインでは、クエリは問題ありませんでした。しかし、ライブ ドメインに移動すると、問題が発生しました。ほとんど何も変更されていませんが、これらの新しい遅いクエリのためにサイト全体が停止しました. 重要な注意事項:

  • 別のドメイン
  • /var/www 内の別のフォルダー
  • 同一DB
  • 同じ DB 資格情報
  • 同じコード
  • 修正を試みてインデックスを追加しました - これは役に立ちませんでした

これらのいずれかがロード時間に影響を与える可能性はありますか?

4

3 に答える 3

2

これはすぐに「答えではない」と評価されますが、単純に皿に載せて手渡すことなく、考えられる解決策を示しています....

 SELECT * FROM ints;
 +---+
 | i |
 +---+
 | 0 |
 | 1 |
 | 2 |
 | 3 |
 | 4 |
 | 5 |
 | 6 |
 | 7 |
 | 8 |
 | 9 |
 +---+

 SELECT x.i, MIN(y.i) FROM ints x LEFT JOIN ints y ON y.i > x.i GROUP BY x.i;
 +---+----------+
 | i | MIN(y.i) |
 +---+----------+
 | 0 |        1 |
 | 1 |        2 |
 | 2 |        3 |
 | 3 |        4 |
 | 4 |        5 |
 | 5 |        6 |
 | 6 |        7 |
 | 7 |        8 |
 | 8 |        9 |
 | 9 |     NULL |
 +---+----------+
于 2013-08-07T10:48:31.157 に答える
1

次の機能がどれだけうまくいくのだろうか。結合操作を文字列操作に置き換えます。

  SELECT shot.hole AS hole, shot.id AS id,
         substring_index(substring_index(shots, ',', find_in_set(shot.id, ss.shots) + 1), ',', -1
                        ) as nextsi,
         substring_index(substring_index(shots, ',', find_in_set(shot.id, ss.shots) - 1), ',', -1
                        ) as prevsi,
         shot.distance AS distance_remaining, shot.type AS hit_type, shot.area AS onto
  FROM shot JOIN
       course
       ON shot.course_id = course.id JOIN
       round
       ON shot.round_id = round.id join
       (select s.round_id, s.hole, group_concat(s.id order by s.shot_number) as shots
        from shot s
        group by s.round_id, s.hole
       ) ss
       on ss.round_id = shot.round_id and ss.hole = shot.hole
  WHERE round.uID = 78

これは完全には機能しないことに注意してください。最初と最後のショットで誤った結果が生成されます。それらの詳細を修正する前に、パフォーマンスがどのようになっているのだろうか。

于 2013-08-07T12:57:31.363 に答える
1

ストロベリーの答えを拡張するには、「事前クエリ」に追加の左結合を実行して、前/次の ID をすべて取得してから、結合して必要な詳細を取得します。

select
      Shot.ID,
      Shot.Hole,
      Shot.Distance as Distance_Remaining,
      Shot.Type as Hit_Type,
      Shot.Area as Onto
      PriorShot.Hole as PriorHole,
      PriorShot.Distance as PriorDistanceRemain,
      NextShot.Hole as NextHole,
      NextShot.Distance as NextDistanceRemain
   from
      ( SELECT 
              shot.id, 
              MIN(nextshot.id) as NextShotID,
              MAX(priorshot.id) as PriorShotID
           FROM 
              round 
                 JOIN shot 
                    on round.id = shot.round_id
                    LEFT JOIN shot nextshot
                       ON shot.round_id = nextshot.round_id
                       AND shot.hole = nextshot.hole
                       AND shot.shot_number < nextshot.shot_number
                    LEFT JOIN shot priorshot
                       ON shot.round_id = priorshot.round_id
                       AND shot.hole = priorshot.hole
                       AND shot.shot_number > priorshot.shot_number
           WHERE
              round.uID = 78
           GROUP BY 
              shot.id ) AllShots
         JOIN Shot
            on AllShots.id = Shot.ID
            LEFT JOIN shot PriorShot
               on AllShots.PriorShotID = PriorShot.ID
            LEFT JOIN shot NextShot
               on AllShots.NextShotID = NextShot.ID

内部クエリは round.uID = 78 のものだけを取得し、必要に応じて次/前に結合できます。結果の列が表示されなかったので、コース テーブルとラウンド テーブルに結合を追加しませんでしたが、簡単に追加できました。

于 2013-08-07T16:37:51.653 に答える