ActiveRecord查询优化:如何分析并提升慢查询性能?
分析并优化查询性能的步骤
1. 用执行计划定位瓶颈
在目标SQL前添加EXPLAIN关键字执行,重点关注以下字段:
type:如果显示ALL说明存在全表扫描,是核心优化点;key:查看实际命中的索引,若为NULL则代表未用到有效索引;rows:预估扫描的行数,数值越大意味着查询要处理的数据量越多;Extra:如果出现Using filesort或Using temporary,说明存在额外排序/临时表开销,需调整逻辑。
2. 针对性优化索引
现有索引无法覆盖查询的核心过滤条件,建议新增以下复合索引:
针对user_placements表
查询的核心过滤条件是user_id = 1(等值匹配)、created_at > 三个月前(范围匹配),再加上deleted_at、notification_sent、responded_at的非空过滤,创建复合索引:
CREATE INDEX idx_user_placements_user_created ON user_placements (user_id, created_at, deleted_at, notification_sent, responded_at);
理由:等值条件放在最前面,接着是范围条件,最后补充其他过滤字段,让数据库能快速定位到目标行,避免全表扫描。
针对placement_campaigns表
查询需要过滤instant = 0、deleted_at IS NULL,同时要关联id字段,创建索引:
CREATE INDEX idx_placement_campaigns_instant_deleted ON placement_campaigns (instant, deleted_at, id);
这样JOIN操作时能快速匹配符合条件的活动记录,避免扫描整个表。
3. 简化实时计算逻辑
查询中的TIMESTAMPDIFF+LEAST是实时计算,数据量大时会增加CPU开销:
- 在
user_placements表新增response_delay_minutes字段(INT类型); - 通过数据库触发器或ActiveRecord的
before_save/before_update回调,在notification_sent或responded_at更新时自动计算并填充该字段; - 后续查询直接
SELECT response_delay_minutes,省去实时计算的开销。
4. 减少无效数据扫描
- 清理软删除数据:如果两张表中有大量
deleted_at IS NOT NULL的软删除数据,定期归档或清理,避免查询时过滤无效数据; - 缩小时间范围:如果业务允许,把查询的时间范围从三个月缩小到更短的周期,大幅减少扫描行数。
5. 预聚合统计数据
如果该查询是统计类需求(不需要实时数据):
- 建立统计数据表(如
user_response_stats),包含user_id、average_delay、stat_date等字段; - 用定时任务(如Sidekiq、数据库事件)每天/每小时预计算平均值并写入统计表;
- 查询时直接从统计表取数,无需每次扫描大量原始数据。
内容的提问来源于stack exchange,提问作者jordan
相关产品推荐
相关产品推荐

