与Rails的备忘录化有很多关系

时间:2018-10-13 20:24:23

标签: ruby-on-rails

是否可以通过备忘录在包含has_many关联的SQL查询上缓存实例变量?在下面的两个示例方法中,some_instance方法将按预期缓存,但some_other_instance将缓存Artist,而不是歌曲关联,这将在每次运行该方法时导致SQL查询。

当方法返回“ ActiveRecord :: Associations :: CollectionProxy”或“ ActiveRecord :: Relation”时,它似乎不会完全缓存。

class Artist < ApplicationRecord
    has_many :artist_songs
    has_many :songs, through: :artist_songs

    def self.some_instance
        @some_instance ||= find(10)
    end

    def self.some_other_instance
        @some_other_instance ||= find(10).songs
    end
end

2 个答案:

答案 0 :(得分:0)

some_instance方法缓存find(10)方法的结果,该方法执行数据库查询并返回一条记录。

但是some_other_instance方法会缓存一个关系对象,而不是数据库查询的结果。实际上,如果您在Artist.some_other_instance; note;结尾)之类的Rails控制台中运行,则不会有任何数据库查询,因为您不使用查询结果。但是,当您只运行Artist.some_other_instance时,会出现查询,因为结果是用来打印的。

因此,要真正缓存some_other_instance方法,您需要添加例如to_a

def self.some_other_instance @some_other_instance ||= find(10).songs.to_a end

但是在这种情况下,该方法将不是“可链接的”。

答案 1 :(得分:0)

to_a提供了用于缓存关系的解决方案。

在下面的日志中,SQL查询花费1883.4ms和构建视图623.4ms。总时间为15053毫秒,这意味着将to_a添加到对象上需要12546.2毫秒。如果我关闭to_a,则总时间将减少到大约2000ms。

建立对象需要这么长时间是正常的吗?

Started GET "/build" for 127.0.0.1 at 2018-10-14 16:35:30 -0700
Processing by ArtistsController#build as HTML
  Artist Load (208.4ms)  SELECT `artists`.`id`, `artists`.`name`, `artists`.`uri`, `artists`.`artwork_url`, updates.popularity, updates.created_at AS pop_created_at, reachupdates.reach, reachupdates.created_at AS reach_created_at FROM `artists` INNER JOIN `updates` ON `updates`.`artist_id` = `artists`.`id` INNER JOIN `reachupdates` ON `reachupdates`.`artist_id` = `artists`.`id` WHERE `artists`.`id` = 1
  Song Load (510.5ms)  SELECT songs.*, songupdates.* FROM `songs` INNER JOIN `artist_songs` ON `artist_songs`.`song_id` = `songs`.`id` INNER JOIN `artists` ON `artists`.`id` = `artist_songs`.`artist_id` INNER JOIN `songupdates` ON `songupdates`.`song_id` = `songs`.`id` WHERE `artists`.`id` = 1
  Playlist Load (1089.2ms)  SELECT playlists.*, playlistupdates.* FROM `playlists` INNER JOIN `playlist_songs` ON `playlist_songs`.`playlist_id` = `playlists`.`id` INNER JOIN `songs` ON `songs`.`id` = `playlist_songs`.`song_id` INNER JOIN `playlistupdates` ON `playlistupdates`.`playlist_id` = `playlists`.`id` LEFT OUTER JOIN `artist_songs` ON `artist_songs`.`song_id` = `songs`.`id` LEFT OUTER JOIN `artists` ON `artists`.`id` = `artist_songs`.`artist_id` WHERE `artists`.`id` = 1 AND `playlists`.`relevant` = 1 AND (playlistupdates.id IN (SELECT MAX(playlistupdates.id) AS id FROM playlistupdates GROUP BY playlistupdates.playlist_id)) ORDER BY `playlistupdates`.`followers` DESC
  Rendering artists/build.html.haml within layouts/application
  Rendered artists/build.html.haml within layouts/application (15.6ms)
  Rendered layouts/_head.html.haml (45.8ms)
  Rendered svg/_settings.html.erb (0.9ms)
  Rendered svg/_search.html.erb (0.4ms)
  Rendered layouts/_header_new.html.haml (73.3ms)
  Rendered shared/_autocomplete-box.html.haml (14.2ms)
Completed 200 OK in 15053ms (Views: 623.4ms | ActiveRecord: 1883.4ms)