rails项目优化 sql优化

因为项目的表数据量比较大,系统经常因为内存满而卡死,所以对整个rails项目进行了一次简单的优化,其中涉及到了几个比较关键的点,记录下来。假设有个product表,数量在百万级别的。

因为是rails项目所以里面会包含一些rails注意事项,还有一些简单的sql语句优化,水平有限,如果有什么不对的地方,还请邮件联系我。

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

1
2
3
Product.all.each do |product|
....
end

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

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

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

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

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

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

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

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

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

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

1
2
3
products = Product.all; false ## 此方法只试用rails3,之后的已经为lazy_load了
product_names = products.pluck(:name)
product_brands = products.pluck(:brand)

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

1
Product.all.pluck(:brand_id).uniq

后来我用distinct来代替了

1
Product.all.pluck('distinct brand_id')

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

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