我们为什么要避免1 + N查询问题?

时间:2013-10-29 17:51:26

标签: sql ruby-on-rails ruby database

听起来有点愚蠢,但我不是数据库专家。

例如,如果我们有User模型和Comment模型,并且每条评论都属于某个用户,则有两种方法可以获取所有评论及其用户:

# 1.
@comments = Comment.all(:include => :user)

# 2. 
@comments = Comment.all()
@users = []
@comments.each do |comment| # Or we do the same loop in embedded code in the view
  @users << User.find(comment.user)
end

我的问题是,由于这两种方法都会获取所有评论及其用户数据(这意味着我们从硬盘驱动器和互联网上读取和传输相同数量的信息),为什么第二种方法被视为不良做法?

2 个答案:

答案 0 :(得分:4)

请允许我说明原因:

Message.count
13228

Benchmark.measure { Message.all.each(&:user) }
16s

Benchmark.measure { Message.all(include: :user).each(&:user) }
2s

有100行,这是一个更真实的提取:

Benchmark.measure { Message.limit(100).each(&:user) }
0.12s

Benchmark.measure { Message.includes(:user).limit(100).each(&:user) }
0.01s

正如您所看到的,数据库速度提高了约10倍,压力也减轻了。

答案 1 :(得分:2)

一次又一次地访问数据库以获取与User记录关联的Comment记录将影响您的应用程序的性能。

如果评论数量太高而你正在循环播放它以获得所有相关用户,那就变得更加缓慢。

Comment.all(:include => :user的情况下,只会一次触发两个查询。一个获得评论,一个获得所有相关用户。