You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效遍历数据库中的大量记录并生成新列表

效率问题根源
  • 原代码存在严重的N+1查询问题:每遍历1条Document记录,就会产生4次对primary_files表的查询,5000条记录就会产生20000+次数据库查询,开销极大
  • Document.all.reverse 会一次性把所有Document记录加载到内存,数据量再增长很容易出现内存溢出
  • 同一关联表的聚合计算重复执行,没有做合并查询
优化方案

最优方案:数据库层面一次性完成聚合查询

直接通过分组聚合把所有计算逻辑放到数据库执行,全程只触发1次SQL查询,5000条数据基本可以毫秒级返回结果,优化后代码如下:

# 1. 关联查询+分组聚合,一次拿到所有需要的计算结果,直接在数据库层完成倒序
document_aggs = Document.left_joins(:primary_files)
                        .group(:id, :document_name, :created_at)
                        .select(
                          :id,
                          :document_name,
                          :created_at,
                          "COUNT(primary_files.id) AS records_count",
                          "SUM(primary_files.amount_credit) AS total_collections",
                          "SUM(CASE WHEN primary_files.status = true THEN primary_files.amount_credit ELSE 0 END) AS reconciled_sum",
                          "SUM(CASE WHEN primary_files.status = false THEN primary_files.amount_credit ELSE 0 END) AS unreconciled_sum"
                        )
                        .order(id: :desc)

# 2. 直接遍历预计算结果生成目标列表,无额外数据库查询
files = document_aggs.map do |doc|
  {
    "id" => doc.id,
    "document_name" => doc.document_name,
    "records_count" => doc.records_count,
    "total_collections" => doc.total_collections || 0,
    "reconciled_sum" => doc.reconciled_sum || 0,
    "unreconciled_sum" => doc.unreconciled_sum || 0,
    "reconciliation_date" => doc.created_at
  }
end

补充性能优化建议

  • 可以给primary_files表添加联合索引add_index :primary_files, [:document_id, :status, :amount_credit],进一步加快聚合查询的速度
  • 如果后续数据量涨到10万+,可以用find_each分批处理避免内存溢出,5000条场景下不需要额外处理

内容的提问来源于stack exchange,提问作者Philip Mutua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:39:03