ユーザーの1クリックで2000レコードINSERTするアクティビティ通知機能を作ったメモ

f:id:technuma:20170511213557p:plain

経緯

ブログサービス ( https://pressblog.me/ ) を運営していて、通知機能を開発することになりました。

通知機能の仕様

  • 「いいね!」を押したらフォロワーに通知
  • コメントしたらフォロワーに通知
  • フォロワーは現在、最大で2000人程度
  • すべてのログイン済みユーザーは、各々の通知ページからフォローしているユーザーのアクティビティ(いいね、コメント内容)を見ることができる
    通知画面↓
    f:id:technuma:20170511203741p:plain

環境

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する仕組みで実装しました。

github.com

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(オプションによる)が走らない