删除了N + 1个查询,但它对我没有帮助。只有40个对象,需要15秒。
我认为有很多Stock.with_translations(I18n.locale)
和Distributor.with_translations(I18n.locale)
db调用,序列化的工作速度很慢。我怎么能重构那个db调用?
class ShopsSerializer < ActiveModel::Serializer
include ActionView::Helpers::SanitizeHelper
attributes :id, :title, :description, :audio_sizes, :stocks_count, :image_sizes, :audio_count, :country
has_many :images, serializer: ShopImageSerializer
has_many :products, serializer: ProductSerializer
def image_sizes
total = 0.0
stocks = Stock.with_translations(I18n.locale).includes(:images).where(city_id: object.id)
stocks.each do |stock|
sum = stock.images.inject(0){|sum, item| sum + item.image_size if item.image.present?} || 0
total += sum
end
total.round(2)
end
def audio_sizes
size = 0.0
Stock.with_translations(I18n.locale).where(city_id: object.id).map{|s| size += s.audio.size if s.audio.present?}
Distributor.with_translations(I18n.locale).where(city_id: object.id).map{|d| size += d.audio.size if d.audio.present?}
size
end
def stocks_count
Stock.with_translations(I18n.locale).where(city_id: object.id).count + Distributor.with_translations(I18n.locale).where(city_id: object.id).count
end
def audio_count
count = 0
Stock.with_translations(I18n.locale).where(city_id: object.id).map do |s|
if s.audio.present?
count += 1
end
end
Distributor.with_translations(I18n.locale).where(city_id: object.id).map do |d|
if d.audio.present?
count += 1
end
end
count
end
end
答案 0 :(得分:1)
理想情况下,您应该在数据库级别移动计算,但我没有时间为您编写此代码。否则你仍然有N + 1问题,因为对于要序列化的每个对象,你要查询东西。
无论如何,在你的情况下获胜至少会进行一次查询,记住它们:
class ShopsSerializer < ActiveModel::Serializer
include ActionView::Helpers::SanitizeHelper
attributes :id, :title, :description, :audio_sizes, :stocks_count, :image_sizes, :audio_count, :country
has_many :images, serializer: ShopImageSerializer
has_many :products, serializer: ProductSerializer
def image_sizes
total = 0.0
stocks.each do |stock|
sum = stock.images.inject(0){|sum, item| sum + item.image_size if item.image.present?} || 0
total += sum
end
total.round(2)
end
def audio_sizes
size = 0.0
stocks.map{|s| size += s.audio.size if s.audio.present?}
distributors.map{|d| size += d.audio.size if d.audio.present?}
size
end
def stocks_count
stocks.count + distributors.count
end
def audio_count
count = 0
stocks.map do |s|
if s.audio.present?
count += 1
end
end
distributors.map do |d|
if d.audio.present?
count += 1
end
end
count
end
private
def stocks
@stocks ||= Stock.with_translations(I18n.locale).includes(:images).where(city_id: object.id)
end
def distributors
@distributors||= Distributor.with_translations(I18n.locale).where(city_id: object.id)
end
end
答案 1 :(得分:1)
使用rails缓存而不是activemodel序列化程序缓存解决了我的问题。 link
答案 2 :(得分:1)
您没有说明您使用的是什么版本的AMS,如何使用序列化程序,或者您的ar模型或关联序列化程序。
你也没有说你尝试了什么,或者你读过什么文档,所以很难知道你自己解决这个问题的投资与要求互联网为你做的工作。如果这听起来很苛刻,抱歉,这只是来自处理开源问题的经验。
那就是说,AMS本身不会为你做任何db操作。如果你想加载任何东西,那么你需要在你的应用程序中做一些事情,这意味着阅读有关关联和查询的rails文档
在询问技术问题时,提供足够的信息是一个常见问题。我建议您查看https://www.chiark.greenend.org.uk/~sgtatham/bugs.html或https://github.com/rails-api/active_model_serializers/blob/f5ec8ed9d4624afa6ede9b39d51d145b53b1f344/CONTRIBUTING.md#filing-an-issue或https://github.com/norman/yourbugreportneedsmore.info/blob/master/index.html
引用最后一个:
您已被定向到此网站,因为您提交了错误报告 一个开源项目,但是你提供的信息太少了 开发人员能够帮助您。这看起来很熟悉吗?
嗨,当我使用&lt; program&gt;时,我收到了一个奇怪的错误,你知道吗? 什么可能是错的?
即使你面前有代码,调试软件也很难。 现在想象一下,尝试在其他人的计算机上调试软件,而不是 任何对代码的访问,而不知道操作系统是什么 计算机,甚至是正在使用的软件版本。你唯一的 提示是“有一个奇怪的错误”,你有50行的1行 堆栈跟踪工作。声音不可能?那是因为它!
如果你想真正解决你的问题,你可以这样做 提交开发人员实际响应的错误报告:
如果你只记得一件事,请记住:再现性 关键。如果我无法重现您的问题,我无法修复它。
有关正确错误报告的更长指南,请检查 Simon Tatham's excellent article。
答案 3 :(得分:1)
Stock.with_translations(I18n.locale).where(city_id: object.id)
到Stock
模型并将其作为范围或范围。它也可能对未来有用。
可能Rails会更好地缓存它。
加快查询速度的一点是向stocks.city_id
添加索引,除非您已经拥有索引。
您还可以按joining tables
检查效果 joins(:images)
代替includes(:images)
答案 4 :(得分:1)
对于您要查询Stock.with_translations(I18n.locale).includes(:images)
一次,Stock.with_translations(I18n.locale)
两次和Distributor.with_translations(I18n.locale)
一次的40个项目中的每一项。
这导致至少40 * 2 + 40 * 2 + 40个查询。
您显然需要一种方法来创建Shop
和Stock
之间的关联,Distributor
,可能与has_many :through
。但是,当您尝试从城市Stock
和Distributor
访问项目时,您可以查询它们并将它们与序列化程序中的选项一起传递,或者您可以按照@建议的那样记忆并运行这些查询。 apneadiving。