是否可以通过备忘录在包含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
答案 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)