スポーツイベントに関するWebアプリケーションの「リーダーボード」に取り組んでいます。すべての選択肢のクイズへの彼らの応答。また、現在のユーザーのランクをリーダーボード内に表示します。MySQL:「グループ化」を使用した低速クエリ - 「tmpテーブルへのコピー」でスタック
このアプリケーションが負荷テストされると、関連する2つのクエリは非常に遅くなり、 "tmpテーブルへのコピー"状態(クエリごとに最大20秒)で多くの時間を費やします。彼らは最終的に処理を行いますが、その間に何百人も積み重ねられます。単独で
応答テーブル内の行の適切な数を与え、各クエリは、(応答で25Kユーザ、例えば200K行)を実行するのに約1秒かかり
Iは、特に、当該テーブルにいくつかのインデックスを追加しましたFK列とwhere文で使用されるものについては、また、応答テーブルにuserID、answerIDのカバリングインデックスを追加しました。
これは、これは結果内のユーザー自身のランクを取得するためのクエリでリーダーボード自体
SELECT users.username, sum(questions.points) as score FROM responses
JOIN answers on responses.answerID = answers.answerID
JOIN questions on answers.questionID = questions.questionID
JOIN users on responses.userID = users.userID
WHERE users.username != '' AND answers.isCorrect
GROUP BY users.userID
ORDER BY score DESC
LIMIT 20
ためのクエリです。別のクエリで最初にスコアを取得した後、スコアの高いユーザーの数をカウントします。
Select count(*) +1 as rank from (
SELECT users.username, sum(questions.points) as score
FROM responses
JOIN answers on responses.answerID = answers.answerID
JOIN questions on answers.questionID = questions.questionID
JOIN users on responses.userID = users.userID
WHERE users.username != '' AND answers.isCorrect
GROUP BY users.userID
HAVING sum(questions.points) > 2431
ORDER BY score DESC
) as result
簡体スキーマは
QUESTIONS
questionID
question
points
ANSWERS (multiple choice answers for question)
answerID
questionID
answer
isCorrect
RESPONSES (the player's choice of answer)
responseID
answerID
userID
が、私はこれらのクエリは漠然と賢明な方法で行われていると思うが、私は私が持っているこれらのいずれかを行うには明らかに、より良い方法があるかどうかを知りたいです考慮されていません。
また、これらのクエリが「tmpテーブルへのコピー」状態でスタックし、サーバーの負荷がかかっているときに処理時間がかかる理由について、誰もが考えていますか?私はそれがディスク上にそれらを作成するかもしれないと思ったが、私はそれが別の状態メッセージであると思う。私はEXPLAINを使用しましたが、私の感想は、これらのクエリで一時テーブルが避けられないということです。したがって、「コピーするtmpテーブル」には時間がかかります
制約:示されていません。ユーザーにはチームIDがあり、クエリもteamIDによってフィルタリングされます。また、図示されていないが、いくつかのイベントが存在し、これらのクエリをeventIDによってフィルタリングすることもできる。また、すべての質問が答えられた時点で正しい答えを持っているわけではありません。将来のある時点で正しい答えが割り当てられるかもしれませんが、スポーツイベントの終わりにはどんな速度でも割り当てられます。システムは、各回答を選択したユーザーの割合を報告します。そのため、スコアをより集約して格納するさまざまな方法が検討されていますが、これらの制約の1つまたは複数と競合するため、破棄されています。これは上に行くには十分である
・ホープ - 多くのおかげで
このをありがとう。あなたの返信を感謝します。私は曖昧に何かを実装することを検討しましたが、サマリーテーブルが再投入されている間にリーダーボードリクエストが来たらどうなりますか? – Polsonby
InnoDBを使用していますか?そうであれば、更新クエリによってサマリテーブルがロックされ、ユーザー要求は2番目にハングアップするか、または生成され、その後正常に完了します。 MyISAMを使用している場合、ストアドプロシージャはサマリーテーブルを明示的にロックして、同じ効果を得られるはずです。このすべてにひどい問題がある場合は、新しいテーブルを作成し、古いテーブルをロックして削除し、古いテーブルの名前に変更することができます。しかし、それはデバッグするための完全なヘアボールです。 –