论坛首页 编程语言技术论坛

分析ROR中获取关联集合size的SQL处理及疑问

浏览 3182 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-30  
假设现在有两个类A,B
class A
  has_many :Bs, :class_name=>'B',:foreign_key=>'b_id'
end
a = A.find(:first)

  如果我仅想知道a.Bs.size()的话,那么在hibernate中就得单独写count语句来获取,如果使用a.getBS().size()的方式时,会先填充list,把所有Bs都初始化,也即会向数据库中发送.size()条SQL语句来初始化对象,影响性能。
  但在ror中,像上面使用a.Bs.size方法的时候,它会先判断Bs是否已经被初始化,如果已经初始化过,则直接返回Bs.size,不需要查询数据库。若尚未初始化,则发送一条count(*)语句,返回总的记录条数。这一点我感觉比hibernate要聪明。

在这个过程中发现一个有趣的现象:
N.times do
  print("a.Bs.size=#{a.Bs.size}");
end

如果a.Bs是可以获取到数据的话,那么上面语句,会发送N条count(*)的SQL。
反之如果a.Bs是空集合,数据库中根本没有相关记录的话,那么系统只会发送一条count(*)的SQL。为什么呢?

思考了一下,ROR是否是这样处理的,如果a.Bs.size>0,则它认为在下次查询时仍然需要去发送count(*)SQL。反之如果a.Bs.size==0,则它认为没必要再去发送count(*)的SQL了?但还是觉得有些离奇。
再次思考之后,是否是这样:如果第一次发现a.Bs.size>0,则它认为a.Bs是不为空的,但是先不去初始化它。而如果size==0,则它认为a.Bs是空值。直接就给a.Bs赋为空记录集了,所以再取a.Bs.size就不需要查询数据库了

另外的一点是,如果代码改成:
print((a.Bs[0] rescue nil));
N.times do
  print("a.Bs.size=#{a.Bs.size}");
end

则只会发送select * from xxx的SQL。相当于初始化了a.Bs集合。在这个基础上再计算a.Bs.size,则不会发送count(*)的SQL,直接返回a.Bs集合的长度了。

这该怎么解释才更合理呢????
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics