前前前.....前段时间,由于自己对length,size,count不熟悉,乱用这计数三兄弟,导致整个网站崩了。而且最主要的是当时还花了很长时间才找到问题的根源(问题藏得太深,各种分析)。
根源
有如下代码
commodity = Commodity.select('catalog_id', 'brand_name')
commodity.count
当我使用count的时候会报错,而使用length和size的时候不会报错
count
每次都会去执行sql查询,结果并没有真正的存储在生命周期内部,但是由于activerecord的缓存机制,所以查询一次后,后面的查询都是使用的缓存结果
想得到返回结果的数量时,所以使用count的时候会报错,是因为select('catalog_id', 'brand_name')
字段之后,再使用count,生成的sql语句是SELECT COUNT(catalog_id, brand_name)
,数据库无法知道我们是要根据catalog_id
存在的值去做统计,还是根据brand_name
存在的值去做统计。如果非要使用count的话,可以在参数里面去声明使用的条件count(:catalog_id)

length
当我们使用length查询某个集合时,length会将这整个集合全部加载到内存中,再去计算他的长度,当把所有的集合全部放到内存之后,他就可以直接返回集合长度,并且非常快。但是如果数据量大的话,可能就会把内存耗光。所以服务器瘫痪的原因应该就是使用length时,他把commodities表以及inclues进来的表全部加载到内存里面,本来这些数据量就大,所以内存吃了很多,导致瘫痪。
size
比较灵活,其实就是一个三元运算,根据条件去判断使用size还是count,如果加载了集合的话就使用length,没有加载的话就使用count。(如下是size源码)
# File activerecord/lib/active_record/relation.rb, line 260
def size
loaded? ? @records.length : count(:all)
end
查询语句比较

网友评论