2

我对 RoR 不是很熟悉,但我的同事已经为我们的一个应用程序编写了这段代码,我觉得这对于一个简单的任务来说太不优化了,而且查询太多。

我们有 3 张桌子。艺术家、专辑和歌曲。艺术家可以有多个专辑。专辑可以有多首歌曲。我们正在尝试根据歌曲表中的字段 Popularity_total 输出前 10 首歌曲。然后还有其他表格可以捕获喜欢等。

def top
     # a list of 10 most played songs in the past week
     @toplistsongs =  Song.select(INDEX_COLUMNS).order("popularity_total,created_at     DESC").limit(10)
     @toplistsongs.each do |song|
      song['urls'] = song.get_song_urls
      song['artist'] = song.get_song_artist
      song['genre'] = song.tag_list
      song['hearts'] = song.likers(User).count
      song['like_status'] = ( current_user!=nil ? current_user.likes?(song) : false )
      song['impressions'] = song.impressionist_count
      song['albums'] = song.get_song_album
    end

    @w = {'top' => 
             {  
                'song' => @toplistsongs
             }
        }
     respond_with(@w)
end

循环内的每次 fetch 都会导致对 db 的命中。我有一种感觉,每首歌曲的循环中都会发生太多查询,而理想情况下,它们都可以使用对所有歌曲的单个查询来完成。任何人都可以建议这是处理事情的标准 Rails 方式还是这完全是糟糕的代码?

感谢所有的帮助。

4

2 回答 2

1

您可以使用ActiveRecord 包含方法来减少数据库查询计数。例如:

 @toplistsongs =  Song.select(INDEX_COLUMNS).order("popularity_total,created_at     DESC").limit(10).includes(:tags, { :songs => :artists }, :urls, :likers)

这将为整个 top 方法产生 5 个查询,并且不依赖于您要呈现的歌曲数量。换句话说,查询的数量是恒定的。

您必须使用 ActiveRecord 关联才能使其工作。我可以看到您正在使用get_song_artist我认为它不是由协会制定的方法。

要在ActiveRecord 关联中建立关系,您必须使用 has_many、has_one 和 belongs_to 运算符。

于 2012-09-20T07:19:05.690 回答
0

这只是一个快速回复。如果您对任何特别的事情有任何困惑,请告诉我。

您的模型定义应该是这样的

class Artist<AR::Base
    has_many :albums
end

class Album<AR::Base
    belongs_to :artist
    has_many :songs
end

class Song<AR::Base
    belongs_to :album
end

你的查找线应该是这样的

@toplistsongs = Song.order("popularity_total, created_at").limit(10).includes(:tags, { :songs => :artists }, :urls, :likers)

应该根据您的popularity_total领域返回前 10 首歌曲。

感谢 Erez Rabih 的包含部分

现在

  • asong.album应该返回Album.Song
  • asong.album.artist应该返回Artist.Song

您可以通过预先加载来加载这些关系。按照链接

tags假设您与和有关系urls

于 2012-09-20T07:18:43.387 回答