Django测验系统大数量试题加载慢的优化方案咨询
Django在线测验系统试卷生成优化方案
1. 用批量数据库操作替代循环单条创建
问题核心大概率是循环创建QuestionDraft和AnswerDraft时,每一条记录都触发一次数据库插入查询,50题以上会产生成百上千次独立查询,累积耗时剧增。改用Django的bulk_create方法批量插入,能将多次查询合并为少数几次,大幅减少数据库交互开销。
示例代码:
# 1. 批量创建QuestionDraft question_drafts = [] for question in selected_questions: q_draft = QuestionDraft( question_id=question.id, exam_id=current_exam.id, # 其他必填字段 ) question_drafts.append(q_draft) QuestionDraft.objects.bulk_create(question_drafts) # 2. 建立Question与QuestionDraft的映射,批量创建AnswerDraft q_id_to_draft = {draft.question_id: draft for draft in question_drafts} answer_drafts = [] for question in selected_questions: q_draft = q_id_to_draft[question.id] # 预取的answers直接遍历,无需再次查询 for answer in question.answers.all(): a_draft = AnswerDraft( question_draft=q_draft, content=answer.content, is_correct=answer.is_correct, # 其他需要复制的字段 ) answer_drafts.append(a_draft) AnswerDraft.objects.bulk_create(answer_drafts)
2. 预关联数据,避免N+1查询
抽取试题时,提前用prefetch_related加载关联的Answer数据,避免循环中每次访问question.answers都触发新的数据库查询。
示例代码:
# 按科目抽取指定数量试题,同时预取关联的答案 selected_questions = Question.objects.filter( subject=target_subject ).prefetch_related('answers')[:required_num]
如果Question和Answer是反向关联,确保Answer模型中定义了related_name,或使用默认的question_set,prefetch_related同样适用。
3. 优化数据库索引
给常用过滤、关联的字段添加索引,提升查询和关联效率:
Question模型的subject字段(按科目过滤试题时用到)QuestionDraft的question、exam外键字段AnswerDraft的question_draft外键字段
示例模型修改:
class Question(models.Model): subject = models.ForeignKey(Subject, on_delete=models.CASCADE, db_index=True) # 其他字段... class QuestionDraft(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE, db_index=True) exam = models.ForeignKey(Exam, on_delete=models.CASCADE, db_index=True) # 其他字段... class AnswerDraft(models.Model): question_draft = models.ForeignKey(QuestionDraft, on_delete=models.CASCADE, db_index=True) # 其他字段...
4. 异步化试卷生成(可选)
如果试卷生成逻辑确实无法在短时间内完成,可以将生成任务异步化,避免前端页面长时间等待:
- 使用Celery等异步任务框架,将试卷生成逻辑封装为异步任务
- 用户触发生成操作后,前端立即返回响应,显示“生成中”状态
- 任务完成后,通过websocket或轮询通知用户,跳转至已生成的试卷页面
5. 精简字段复制
检查AnswerDraft是否复制了Answer中所有字段,只保留学生作答和判分必需的字段,减少单条记录的数据量,降低插入和存储开销。比如无需复制的冗余描述字段,可以直接省略。
内容的提问来源于stack exchange,提问作者Giorgio Scarso
相关产品推荐
相关产品推荐

