我正在研究一個與應用有關的體育賽事的「排行榜」,該體育賽事根據他們的分數報告前20位用戶所有他們對多項選擇測驗的迴應。它還在排行榜中顯示當前用戶自己的排名。MySQL:緩慢查詢使用「group by」 - 卡在「複製到tmp表」
當此應用程序正在進行負載測試時,有關的兩個查詢變得非常慢,在「複製到tmp表」狀態(每個查詢最多20秒)中花費了大量時間。他們最終做了處理,但同時數百人可以堆積起來。
在隔離給出合理的數目在響應表中的行,每個查詢需要約1秒至執行(25K用戶,例如,在響應200K行)
我已經添加一些索引有關的表,特別是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表」需要很長時間
約束:未顯示,用戶具有teamID,查詢也通過teamID進行過濾。也沒有顯示,有幾個事件,這些查詢也可以通過eventID過濾。此外,並非所有問題在回答時都有正確的答案。在未來某個時候可能會分配正確的答案,但無論如何在體育賽事結束時。系統報告用戶選擇每個答案的百分比。因此,以更加合計的方式存儲分數的各種方式已被考慮但被丟棄,因爲它們與一個或多個這些限制相沖突。
希望這足以去 - 許多感謝
感謝這個;感謝您的回覆。我認爲實現了一些模糊的類似的東西,但是在彙總表重新填充時,如果排行榜請求進入,會發生什麼? – Polsonby 2012-01-17 15:40:25
你在使用InnoDB嗎?如果是這樣,您的更新查詢將鎖定您的彙總表,並且用戶請求將在第二秒鐘或之後掛起以生成它,然後正常完成。如果你正在使用MyISAM,你的存儲過程應該可能顯式地鎖定彙總表以獲得相同的效果。如果所有這些都出現了一個可怕的問題,您可以嘗試創建一個新表格,然後鎖定舊錶格,刪除它,並將新表格重新命名爲舊名稱。但這是一個全面的毛球來調試。 – 2012-01-18 02:41:57