Rails API控制器性能优化咨询:Dashboard接口响应慢问题
Rails API Dashboard 性能优化方案
一、数据库查询层优化
- 合并重复过滤逻辑:
filter_and_group_leads被调用3次,每次重复执行相同过滤规则,改为一次查询获取所有符合条件的Lead,再按technology分组到A/B/C集合,避免重复过滤带来的数据库开销。 - 消灭N+1查询:
set_old_and_new_country_tech_hash_A_and_B中循环查询Lead的逻辑,改为先收集所有需要的ID,再批量查询:Lead.where(id: all_ids).select(@fields.pluck(:name)).group_by { |lead| [lead.country, lead.technology] },一次性获取数据后再分组处理。lead_user_summary中循环查询assignedLeads1的逻辑,改为先批量获取所有用户的Lead数据,再按user_id分组,避免循环查询。
- 优化年份查询:把
Lead.pluck(:created_at).map { |x| x.year }.uniq替换为Lead.distinct.pluck('EXTRACT(YEAR FROM created_at)'),让数据库直接计算年份并去重,减少Ruby端内存处理。 - 添加复合索引:针对Lead表常用过滤和分组字段创建复合索引,比如:
根据实际查询频率调整索引组合,加速过滤和分组操作。add_index :leads, [:created_at, :country, :technology] add_index :leads, [:user_id, :is_closed, :created_at]
二、代码逻辑简化与内存优化
- 提取通用方法:
set_old_and_new_country_tech_hash_A_and_B中A/B/C三段逻辑完全重复,提取成通用方法,接收分组参数(A/B/C)和对应哈希变量,减少冗余代码。 - 简化Hash操作:将
Hash[@technology_hash_A.sort_by{|k, v| v}].keys简化为@technology_hash_A.sort_by { |_, v| v }.map(&:first),避免不必要的Hash转换。 - 清理无用实例变量:及时清理不再使用的实例变量(如
@country_tech_hash_id_A、@new_country_tech_hash_id_A等),减少内存占用,避免GC频繁触发导致响应时间波动。
三、缓存策略升级
- 请求级结果缓存:根据请求的所有参数(user_id、from_date、to_date、source、is_closed等)组合缓存键,缓存整个
dashboard_data_a的响应结果:
针对实时性要求不高的场景,设置合理过期时间,避免重复计算。cache_key = ["dashboard_data_a", params.permit(:user_id, :from_date, :to_date, :source, :is_closed, ...)].cache_key Rails.cache.fetch(cache_key, expires_in: 15.minutes) do # 原业务逻辑代码 end - 缓存预热:针对常用参数组合(比如当月数据、默认过滤条件),在后台定时任务中提前计算并缓存,减少用户首次请求等待时间。
四、异步与响应优化
- 非核心数据异步加载:如果
lead_user_summary中的assigned_leads不是Dashboard必须实时展示的内容,可只返回用户统计数据,前端后续通过单独API请求加载具体Lead列表,减少主请求的数据量和处理时间。 - 分页返回数据:如果返回的Lead数据量较大,对
assigned_leads等列表数据实现分页,前端按需加载,避免一次性加载大量数据导致的内存和IO波动。
五、性能监控与排查
- 使用
bulletgem检测N+1查询和未使用的预加载,定位隐藏的查询问题。 - 集成
rack-mini-profiler查看每个请求的耗时分布,包括数据库查询、Ruby代码执行等环节,精准定位慢代码。 - 查看数据库查询执行计划(比如PostgreSQL的
EXPLAIN ANALYZE),确认是否存在全表扫描或索引未命中的情况,调整查询语句或索引。
内容的提问来源于stack exchange,提问作者Ridham Patel
相关产品推荐
相关产品推荐

