Rails 分享一点 Rails 开发时遇到的代码问题

tianlitao · 2016年07月10日 · 最后由 501225658 回复于 2016年07月17日 · 2680 次阅读

最近项目经常会内存被占满,后来看了过了一遍代码,整理了一下遇到的问题,其实大部分都是中文指南上有讲的,可能平时都不大注意写法。

假设有个 product 表,数量在百万级别的。

1.如果查询出来的数据特别多需要遍历,比如可能会有这种情况

Product.all.each do |product|
  ....
end

这种做法是致命的,切记不要这么做,因为一次读出所有的 product 数据不仅慢,如果特别多,会把内存撑满的。一定要用 find_each 或 find_in_batches 代替 each,中文指南的文档在这里

2.见到有些同事喜欢用这种写法

Product.sell.map(&:name)
SELECT `products`.* FROM `products`  WHERE (products.sell = 1)

这样写在数据量大得时候查询会非常慢,并且占用内存会非常多,如果可以替换,我觉得这样的写法更好

Product.sell.pluck(:name)
SELECT `products`.`name` FROM `products`  WHERE (products.sell = 1)

不仅查询的快,而且占用内存也会极大的降低。

3.使用 includes,防止 n+1 查询,文档

4.防止预查询,有的时候我们会把一个查询语句赋给一个值,然后后边调用,比如说:

products = Product.all
product_names = products.pluck(:name)
product_brands = products.pluck(:brand)

直接这样写的话在第一句的时候会直接把所有的 product 查询出来,不仅耗时,而且占用内存。防止预查询的做法是

products = Product.all; false
product_names = products.pluck(:name)
product_brands = products.pluck(:brand)

5.查看日志的时候还找到了一个比较费时的 sql

Product.all.pluck(:brand_id).uniq

后来我用 distinct 来代替了

Product.all.pluck('distinct brand_id')

这样虽说加长了 sql 得运行时间但是减少了返回的数据量以及内存占用。

6.使用 explain 来优化 sql,并建立相应的索引

如果有更好的写法,或者其它比较需要注意的地方,欢迎指导 😄

第四而不太理解?有什么区别吗?

第四条,两次 pluck 会导致查询 2 次,而且加不加 false 都一样,不会立即执行.; 第五条只用 distinct 还好,如果加上 order by,会导致创建临时表。速度比在 rails 代码里加运行 uniq 慢得多。

也感觉第 4 点是不成立的。

@easonlovewan @happyming9527 @qinfanpeng 我重新看了一下第四点的确是有误的,不好意思,最后找出来是因为有包含的这个方法导致的

products.select{|product| product.brand_id}

第四条在 rails3 的时代是成立的,4 时代的 all 已经变成 lazy load 了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号