基于Active Record joins与group by的品牌库存统计查询优化问询
完全可以通过Active Record的关联查询和分组聚合能力实现性能升级,优化后仅需1次SQL查询即可拿到所有结果,既规避了Ruby层多轮循环的内存损耗,也彻底解决了N+1查询品牌的问题,同时还能修复原实现中商品多sku导致计数重复的逻辑bug。
优化后的实现代码
# 单SQL完成关联、分组、聚合统计 brand_stats = Brand.joins(items: :skus) .where(items: { category_id: params[:id] }) .group('brands.id, brands.name') .select( 'brands.id', 'brands.name', # 统计品牌下总商品数,加DISTINCT避免多sku重复计数 'COUNT(DISTINCT items.id) AS all_item_count', # 统计有可用库存的商品数:只要有任意一个sku库存>0就算 'COUNT(DISTINCT CASE WHEN item_skus.number_of_stock > 0 THEN items.id END) AS stock_available_item_count' ) # 直接转换为要求的返回格式,无需额外循环处理 render json: { brandCounts: brand_stats.map do |stat| { id: stat.id, name: stat.name, stockAvailableItemCount: stat.stock_available_item_count, allItemCount: stat.all_item_count } end }
补充说明
如果需要返回没有对应分类商品的品牌(计数为0),把joins替换为left_joins即可,聚合函数会自动对无数据的品牌返回0值。
优化后的数据统计逻辑完全交给更擅长做批量计算的数据库层执行,相比原实现的内存中循环处理+N+1查询,在数据量越大的场景下性能提升越明显。
内容的提问来源于stack exchange,提问作者Ragnar921
相关产品推荐
相关产品推荐

