是否可以通过对包含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发布于 2018-10-14 17:06:16
some_instance方法缓存find(10)方法的结果,该方法执行DB query并返回一条记录。
但是some_other_instance方法缓存的是关系对象,而不是DB查询的结果。实际上,如果您在像Artist.some_other_instance;这样的rails控制台中运行(注意,在的末尾是),就不会有任何DB查询,因为您没有使用查询的结果。但是,当您只运行Artist.some_other_instance时,将会出现查询,因为结果是用来打印的。
因此,要真正缓存some_other_instance方法,您需要添加类似to_a的内容,例如:
def self.some_other_instance @some_other_instance ||= find(10).songs.to_a end
但在这种情况下,此方法将不是“可链接的”。
发布于 2018-10-15 09:40:30
to_a提供了缓存关系的解决方案。
在下面的日志中,SQL查询耗时1883.4ms,构建视图耗时623.4ms。总时间是15053ms,这意味着在对象上添加to_a需要12546.2ms。如果我关闭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)https://stackoverflow.com/questions/52797006
复制相似问题