Rails"学生考试"应用程序,提高性能

时间:2016-05-03 06:45:26

标签: ruby-on-rails postgresql

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

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

  • 工具(评估)
  • 问题
  • 能力(问题属性,我有更多,但行为是相同的)
  • 内容(其他属性)
  • 替代
  • 答案(存储学生和替代选择)
  • 指南(存储问题+正确的替代方案)
  • 学生

我需要生成报告,例如,通过能力,内容,每个学生的成功列表等成功分类,等等。

我实际上是通过控制器管理这个代码,如下所示:

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

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日志都会变得疯狂,查询量很大。

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

问候

1 个答案:

答案 0 :(得分:0)

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

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

使用此作为参考,您现在也应该能够优化其他参考。