减少 Rails 中的数据库命中 [英] Reducing database hits in Rails

查看:43
本文介绍了减少 Rails 中的数据库命中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个模型,projectswords,其中 project has_many :words(words 实际上只是一个保存单词数量的模型每天为每个项目编写.

I have two models, projects and words where project has_many :words (words is really just a model that holds the quantity of words written each day for each project.

我有一个视图,我是这样构建的,它显示了项目从开始到结束的所有日子,以及当天写了多少字(如果有的话):

I have a view that I build like this, which shows all the days from start to end in the project and how many, if any words were written on that day:

<% project_range(@project.start, @project.end).each do |day| %>
    <%= day %>
    <%= get_word_count_by_date(@project, day ) %>
<% end %>

在我的助手中:

def project_range(start, finish)
  project_days = (start..finish).collect
end

def get_word_count_by_date(project, date)
  word_count = Word.find_by_project_id_and_wrote_on(project, date)
  if word_count
    word_count.quantity
  else
    0
  end
end

问题是,在视图中,它经常影响我的数据库.例如,如果项目是 30 天,我得到:

Trouble is, in the view, that hits my database a lot. For example, if the project is 30 days, I get:

  Word Load (0.2ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-01' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-02' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-03' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-04' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-05' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-06' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-07' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-08' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-09' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-10' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-11' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-12' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-13' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-14' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-15' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-16' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-17' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-18' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-19' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-20' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-21' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-22' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-23' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-24' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-25' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-26' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-27' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-28' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-29' LIMIT 1
  Word Load (0.1ms)  SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-30' LIMIT 1

有没有办法在不查询项目长度的每一天的情况下做到这一点?我尝试首先加载项目的所有单词,但无法弄清楚如何在其中获得零天数.

Is there a way to do this without querying every single day in the length of the project? I tried starting by loading all of a project's words first, but couldn't figure out how to get the days with zero in there.

推荐答案

您可以使用块助手来保持清洁并避免查找它们:

You could use a block helper to keep it clean and avoid looking them up:

def project_range(project, start, finish, &blk)
  words = project.words.where(:wrote_on => start..finish)
  word_map = words.index_by(&:wrote_on)
  for day in start..finish
    word_count = word_map[day] ? word_map[day].quantity : 0
    blk.call(day, word_count)
  end
end

然后像这样使用

<% project_range(project, start, finish) do |day, word_count| %>
   <%= day %>
   <%= word_count %>
<% end %>

您也可以稍微清理一下帮助程序(避免在其中包含 SQL),可能是通过传递预取单词列表或使用 scope

You could also clean up the helper a bit (avoid having SQL in it), maybe by passing the list of pre-fetched words or using a scope

m_x 建议在 wrote_on 上使用 start..finish where 子句,它更干净!

m_x suggested the start..finish where clause on wrote_on which is cleaner!

这篇关于减少 Rails 中的数据库命中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆