SELECT q.QuestionId,
IFNULL((0 - correct_cnt) / (correct_cnt + wrong_cnt), 1) AS weight
FROM Question q
LEFT JOIN AnswerResult a ON a.QuestionId = q.QuestionId
WHERE a.UserId = {UserId}
ORDER BY weight;
問題:
IFNULL() 函數計算不可用索引。LEFT JOIN 產生巨大笛卡爾積,且 AnswerResult 頻繁讀寫易觸發鎖爭用。在 AnswerResult 增加 weight 列,由應用層或觸發器維護:weight = (0 - correct) / (correct + wrong),區間 [-1, 0]。未做題權重視為 1。
SELECT QuestionId
FROM Question
WHERE KnowledgePoint = {Code}
AND QuestionId NOT IN (
SELECT QuestionId
FROM AnswerResult
INNER JOIN Question USING (QuestionId)
WHERE UserId = {UserId} AND Question.KnowledgePoint = {Code}
);
優化點: 子查詢先按 UserId + KnowledgePoint 過濾,大幅縮小 NOT IN 集合。
SELECT QuestionId
FROM AnswerResult
INNER JOIN Question USING (QuestionId)
WHERE UserId = {UserId}
AND KnowledgePoint = {Code}
AND correct_cnt = 0
ORDER BY wrong_cnt DESC;
SELECT QuestionId
FROM AnswerResult
INNER JOIN Question USING (QuestionId)
WHERE UserId = {UserId}
AND KnowledgePoint = {Code}
AND correct_cnt > 0
ORDER BY weight DESC;
A 場景的 NOT IN 仍有性能隱患(子查詢結果集較大時)。可嘗試:
LEFT JOIN ... IS NULL 或 NOT EXISTS,配合覆蓋索引。WHERE QuestionId NOT IN (...) 传参。關於 JOIN 與冗余的取捨: JOIN 非性能殺手,關鍵在索引設計與結果集大小。高併發海量寫入場景下,冗余字段更新維護成本極高,需權衡讀寫比例、一致性要求決策。