首页 > 解决方案 > 避免在 ActiveRecord 中进行重复查询 - Ruby on Rails

问题描述

我有一段带有一些简单查询的代码,我试图通过将它们压缩成一个查询来优化它。但我不知道怎么做。

posts = Post.where(category: "article")
num_posts = posts.count
first_post = posts.first
posts_with_updated_name = posts.map { |post| post[:name] = "UPDATE_" + post[:name] }

我希望有一个将在第一行执行的查询,然后发布一个数组,在该数组上执行第 2、3 和 4 行的操作。相反,我得到的是我有 3 个单独的查询. 知道如何将其优化为单个查询吗?

LE:你可以假设num_posts和只是我以后需要的first_post变量posts_with_updated_name

标签: ruby-on-railsactiverecord

解决方案


因为将ActiveRecord::Relation对象转换Array为大型数据库可能会消耗大量内存(甚至可能耗尽内存),所以我会执行以下操作,它仍然会使用(2 + 批数)SQL 查询,但是从长远来看,您的应用程序可以扩展。

posts = Post.where(category: "article")
num_posts = posts.count
first_post = posts.first

# || is a PostgreSQL operator for string concatenation
# if you are using MySQL check out CONCAT instead
posts_with_updated_name = posts.select('posts.*', "'UPDATE_' || name AS updated_name")

# example usage
posts_with_updated_name.find_each do |post|
  puts post.id
  puts post.name
  puts post.updated_name
end

# example output:
# 6
# 'Spider Man is Back'
# 'UPDATE_Spider Man is Back'
# 84
# 'Hello World'
# 'UPDATE_Hello World'

推荐解决方案

1.临时“更新名称”

我不会将“更新的名称”存储到变量中,但我只会根据需要附加/前置字符串,如下所示:

posts = Post.where(category: "article")
num_posts = posts.count
first_post = posts.first

# somewhere in your code where you are actually already gonna be looping over `posts`
posts.find_each do |post|
  updated_name = "UPDATE_#{post.name}'"
  # do something here about updated name
end

2.永久“更新名称”

或者......如果这个“更新名称”值是整个应用程序的永久逻辑,那么只需在模型中编写一个方法:

应用程序/模型/post.rb

class Post < ApplicationRecord
  # ...

  def updated_name
    "UPDATE_#{name}"
  end
end

然后在您的代码中,您只需执行以下操作,而无需设置“更新名称”的值,

posts = Post.where(category: "article")
num_posts = posts.count
first_post = posts.first

# example:
puts first_post.updated_name
# => 'UPDATE_Hello World'

推荐阅读