【问题标题】:Rails "students exam" app , improving performanceRails“学生考试”应用,提高成绩
【发布时间】:2016-05-03 06:45:26
【问题描述】:

我阅读了几个问题并安装了 Bullet gem 以避免 N+1 问题但仍然没有运气。我正在使用 Postgre

我正在开发一个考试应用程序,课程是:

  • 仪器(评估)
  • 问题
  • 能力(问题属性,我有更多但行为相同)
  • 内容(另一个属性)
  • 另类
  • Answer(存储学生和备选方案)
  • 指南(存储问题 + 正确选项)
  • 学生

我需要生成报告,例如,按能力、内容、每个学生的成功列表等分组的班级成功率等。

我实际上是通过控制器使用这样的代码来管理它的:

建立一个表格,其中包含一个评估中包含的能力、问题数量以及每个能力的班级成功百分比

def habilidad_pme
  @pme_abilities = @instrument.evaluation.questions.map{|q| q.pme_ability }.uniq
  @pme_table = []
  @pme_abilities.each do |pmea|
    nombre_pmea = pmea.nombre
    cantidad_preguntas = @instrument.evaluation.questions.map{|q| q if q.pme_ability_id == pmea.id  }.compact.count
    ccpme = cantidad_correctas_pme(pmea)
    porcentaje = @asistencia > 0 ? (ccpme/(cantidad_preguntas*@asistencia.to_f)*100).to_i : 0
    @pme_table << { nombre_pme: nombre_pmea, cantidad_preguntas: cantidad_preguntas, porcentaje: porcentaje }
  end
  @pme_table
end



def cantidad_correctas_pme(pme)
  preg = @instrument.evaluation.questions.map{|q| q if q.pme_ability_id == pme.id  }.compact
  correctas = 0
  preg.each do |p|
    Answer.where(question_id: p.id, proccess_instrument: @proccess_instrument).each do |a|
      if a.letra == @instrument.guides.find_by(question_id: p.id).alternative_index
        correctas+=1
      end
    end
  end
  correctas
end

每个问题的正确答案数量

def cantidad_correctas(question)
  correctas = 0
  Answer.where(question_id: question.id, proccess_instrument: @proccess_instrument).each do |a|
    if a.letra == @instrument.guides.find_by(question_id: question.id).alternative_index
      correctas+=1
    end
  end
  correctas
end

按能力内容分组的问题正确答案的数量

def habilidad_contenido_pme
  @pmes = @instrument.evaluation.questions.map{ |q| q.pme_ability }.uniq
  @pme_content_table = []
  @pmes.each do |pm|
    pme_parcial = []
    preguntas_pme = @instrument.evaluation.questions.where(:pme_ability_id => pm.id).joins(:content).group('contents.id').count
    preguntas_pme.each do |key,value| 
      contenido = Content.find(key.to_i)
      cc = cantidad_correctas_pme_contenido(pm,contenido)
      porcentaje = @asistencia > 0 ? (cc/(value*@asistencia.to_f)*100).to_i : 0
      pme_parcial << {nombre_pme: pm.nombre, nombre_contenido: contenido.nombre, cantidad_preguntas: value, porcentaje: porcentaje }
    end
    @pme_content_table << pme_parcial
  end
  @pme_content_table
end

def cantidad_correctas_pme_contenido(pme,content)
  preg = @instrument.evaluation.questions.map{|q| q if q.pme_ability_id == pme.id && q.content_id == content.id }.compact
  correctas = 0
  preg.each do |p|
    Answer.where(question_id: p.id, proccess_instrument: @proccess_instrument).each do |a|
      if a.letra == @instrument.guides.find_by(question_id: p.id).alternative_index
        correctas+=1
      end
    end
  end
  correctas
end

有效,但在我看来它非常慢,我必须在每个报告中使用大约 10 次这样的方法(使用不同的问题属性),一个班级有 30 个学生,每个学生回答大约 30 个问题。

生成1份报告大约需要40秒-1分钟,每次生成报告时rails log都会变得疯狂,查询量很大。

我认为这里的解决方案是每个表使用 1 个大查询,但我找不到开始的方法。

问候

【问题讨论】:

标签: ruby-on-rails postgresql


【解决方案1】:

我只能假设模型(关系)的样子,因此您可能需要调整以下内容才能正常工作。可能有比这更优化的解决方案,但我不想更改您的实现。

def habilidad_pme
  @pme_abilities = PmeAbility.includes(question: {evaluation: :instrument}).where(instruments: {id: @instrument.id})
  @pme_table = []
  @pme_abilities.find_each do |pmea|
    nombre_pmea = pmea.nombre
    cantidad_preguntas = @instrument.evaluation.questions.where(pme_ability_id: pmea.id).count
    ccpme = cantidad_correctas_pme(pmea)
    porcentaje = @asistencia > 0 ? (ccpme/(cantidad_preguntas*@asistencia.to_f)*100).to_i : 0
    @pme_table << { nombre_pme: nombre_pmea, cantidad_preguntas: cantidad_preguntas, porcentaje: porcentaje }
  end
  @pme_table
end

def cantidad_correctas_pme(pme)
  preg = @instrument.evaluation.questions.where(pme_ability_id: pme.id)
  correctas = 0
  preg.find_each do |p|
    correctas += Answer.where(question_id: p.id, proccess_instrument: @proccess_instrument, letra: @instrument.guides.find_by(question_id: p.id).alternative_index).count
  end
  correctas
end

以此为参考,您现在应该也可以优化其他的了。

【讨论】:

  • 我在使用 habilidad_pme 时遇到错误,我的错是没有指定关系:PmeAbility has_many :questions Question belongs_to :pme_ability belongs_to :content Answer belongs_to :question belongs_to :student Instrument belongs_to :evaluation has_many :guides Guide belongs_to :instrument belongs_to :question belongs_to :alternative
  • 错误是什么?你的Question has_many :evaluations 吗?回答你的问题有点困难。如果我需要很长时间才能回复,您可以手动从我的代码中更改这部分 .includes(...)(第 2 行)。根据关联使它们成为复数或单数。例如,既然您说PmeAbility has_many :questions,那么我将不得不将第二行中的答案更新为@pme_abilities = PmeAbility.includes(questions: ...) 但是对于.where() 方法,它应该始终是复数(与表名相同)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2017-06-08
  • 2021-01-16
相关资源
最近更新 更多