Rails-渴望加载

时间:2018-07-31 12:21:42

标签: ruby-on-rails ruby eager-loading

我有3个关联的表:coveralls.ioElmentMeasurement

元素Image度量

度量has_many图像,也包括图像has_many度量(N-N关联)


如何减少

中的查询数量
has_many

对于此代码,每次测量都有N个查询。我可以用这样的东西最小化吗:

images = @element.measurements.map {|e| e.images}.reject!(&:blank?)
images.flatten.map {|i| i.file.url}

查询:`

@element.measurements.joins(:images).select('images.file')

1 个答案:

答案 0 :(得分:1)

在这里逐步替换:

images = @element.measurements.map {|e| e.images}.reject!(&:blank?)

对于这一行代码,最好产生下一个关系

has_many :images, through: :measurements
# OR for better naming
has_many :measurement_images, through: :measurements, source: :images

然后您可以做:

images = @element.measurement_images

哪个将执行下一个SQL

SELECT * 
FROM images 
INNER JOIN measurements 
ON measurements.id = images.measurement_id
WHERE measurements.element_id = $1

因此无需INNER JOIN来拒绝空白图像,只需这样做即可,丢弃不匹配的记录,检出the doc

在创建此has_many through关系之后,下一个代码将不会产生任何N + 1个问题:

images.map {|i| i.file.url}

此外,您可以通过添加#select来最小化输出,但是我不建议您这样做,因为它会使代码变得非常复杂,并且与图像库的实现紧密相关,因此在更新库的情况下,您可以破坏密码。 但请注意,如果您将paperclip gem与默认的URL生成模式一起使用,则可以执行以下操作:

image_ulrs = @element
  .measurement_images
  .select(
    :id,
    :type, # if you have STI model
    :<your_file_field>_file_name, 
    :<your_file_field>_updated_at
  ).map { |i| i.file.url }

<your_file_field> 是第一个传递给has_attached_file的参数,例如

has_attached_file :attachment

将导致

  ...  
  .select(
    :id,
    :type, # if you have STI model
    :attachment_file_name, 
    :attachment_updated_at
  )

但是我再次建议这样做,因为它不会带来很多性能改进,但将来可能会令人头疼。