ユーザーの1クリックで2000レコードINSERTするアクティビティ通知機能を作ったメモ
経緯
ブログサービス ( https://pressblog.me/ ) を運営していて、通知機能を開発することになりました。
通知機能の仕様
- 「いいね!」を押したらフォロワーに通知
- コメントしたらフォロワーに通知
- フォロワーは現在、最大で2000人程度
- すべてのログイン済みユーザーは、各々の通知ページからフォローしているユーザーのアクティビティ(いいね、コメント内容)を見ることができる
通知画面↓
環境
Rails 4.2
MySQL 5.6
大変だったところ
- フォロワー数に比例してINSERT文を増やす必要があった
例:2000フォロワーいるユーザーが、「いいね!」を押してコメントをしたら4000レコードINSERTする必要がある
(eachで回して4000回save走らせたら mac book air のローカル環境で4分くらいかかってつらい) - ログイン済みユーザーであれば手軽なアクティビティ(いいね、コメント)でガンガンINSERTが走ってしまう
解決方法
activerecord-importというgemを利用して、BULK INSERTをすることで解決しました
(アドバイスいただいた先輩に圧倒的感謝)
validate が走る仕組みもあるものの、速度を重視するためvalidateなしでBULK INSERTする仕組みで実装しました。
wikiにexampleが書かれていて分かりやすかったです。
Home · zdennis/activerecord-import Wiki · GitHub
validationの true,false, ○件ずつ実行もできる例もあります。
Examples · zdennis/activerecord-import Wiki · GitHub
mac book airでいろいろ立ち上げながら計測していたのでいろいろスペック不足ではありますが、 ↓のように改善されました。
each で 4000回 save | activerecord-import で BULK INSERT |
---|---|
4分程度 | 4秒 |
注意点
便利なgemではありますが、使い方を少し間違えると罠にハマるので以下注意です。
- 内部でSQL文を結合して発行しているため、一度に実行できるSQL文の最大サイズを超えないように気をつける
MySQL :: MySQL 5.6 リファレンスマニュアル :: B.5.2.10 パケットが大きすぎます
- Railsが提供している after_save, before_save, validate(オプションによる)が走らない