如何借助Searchkick加速200万条记录的CSV导入流程?
批量调度Worker,避免逐行触发
别给每一行单独发Sidekiq任务,把CSV按1000-5000条为一组分成批次,每个Worker处理整批数据。这样能砍掉大量Sidekiq调度的额外开销,避免小任务堆积拖慢整体速度。比如读取CSV时按批次分组,调用BatchProcessingWorker.perform_async(batch_data),在Worker内部处理整批逻辑。优化Searchkick查询,减少重复检索
如果多条CSV行对应同一个数据库记录,先把所有需要查询的条件(比如ID、关键词)提取出来去重,用Searchkick批量查询后再和CSV行做映射。比如用TargetModel.search(term, where: {id: unique_ids}, load: true)一次性获取所有匹配记录,再批量关联对应的CSV数据,避免重复调用Searchkick造成的浪费。批量创建新记录,替换逐条插入
绝对不要在Worker里逐条调用Model.create,收集好所有要创建的记录数据后,用Rails自带的Model.insert_all(Rails 6+)或者activerecord-importgem做批量插入。数据库批量插入的性能比单条插入高几个数量级,能把插入耗时压缩到原来的几十分之一。注意:
insert_all不会触发模型回调和验证,如果需要验证,先在内存里批量验证数据有效性,再执行插入;如果必须用回调,可考虑牺牲一点性能用create!的批量版本。数据库层面的针对性优化
- 临时关闭目标表的索引和外键约束,完成批量插入后再重建。索引会大幅减慢插入速度,百万级数据下这个优化效果尤其明显。
- 调大数据库连接池大小,确保Sidekiq有足够的连接处理批量操作,避免因等待连接阻塞任务。
- 用PostgreSQL的
COPY命令(activerecord-import支持),这比普通的批量插入更快,适合超大量数据的写入。
Sidekiq配置调优
- 根据服务器CPU核心数增加Sidekiq并发数,比如设置
concurrency: 16,但要同步调大数据库连接池,避免连接耗尽。 - 用
sidekiq-batch插件管理批量任务,方便跟踪进度、重试失败批次,同时进一步降低调度开销。
- 根据服务器CPU核心数增加Sidekiq并发数,比如设置
CSV预处理提速
- 先清洗CSV数据:过滤无效行、去重、排序,减少后续Worker的无效操作。
- 用
smarter_csv这类更快的解析库代替Ruby标准库的CSV,大文件解析速度能提升不少。
内容的提问来源于stack exchange,提问作者Anna K

