[大量データ]Laravelで100万データのパフォーマンス改善した話
背景
著者のプロフィール
・SaaSを提供している自社開発企業で開発。
・エンジニア歴2年強。
・Laravel経験も2年強。
経緯
・2021年から大量の従業員を抱える企業様が自社サービスを契約することになり、それまで潜んでいたパフォーマンス問題が露呈。
・2021年には対応する工数を確保できず2022年から対応することになった。
データ構造
・契約している企業様の従業員1人につき複数データがぶらさがっている状態。1対Nの関係。
↓こんな感じ
データ件数
・従業員数10万件
・従業員に対してぶらさがっているデータを併せると100万超データ
チューニング結果
機能A
1000分→84分→60分
左から1回目2回目・・・
機能B
90分→60分
原因&やったこと
機能A
インデックスを貼っていなかった
1000分→84分で劇的に速度改善したのは単純にインデックスを貼っていなかったことが原因だった。
(なぜ昨年はこれでいけたのだろうか。。。)
insertしていたところをbulk insertに変更
単純にinsertをしているとその都度クエリを発行するので、データ件数が増えれば増えるほどパフォーマンスに影響を及ぼす。
例:insertする場合
$employees = [
[
'user_id' => 1,
'name' => 'hoge'
],
[
'user_id' => 2,
'name' => 'fuga'
],
[
'user_id' => 3,
'name' => 'hogera'
]
];
foreach ($employees as $employee) {
Post::create($employee);
}
そこで使うのがbulk insertである。
bulk insertをすることで数万回発行していたクエリを数十回で済むようになった。
例:bulk insertする場合
$employees = [
[
'user_id' => 1,
'name' => 'hoge'
],
[
'user_id' => 2,
'name' => 'fuga'
],
[
'user_id' => 3,
'name' => 'hogera'
]
];
Post::insert($employees);
これによって84分→60分と約24分ほど短縮させることができた。
機能B
キャッシュの利用を見直した
LaravelでDBへのアクセス回数を減らす目的でキャッシュを利用していたが、それが仇となった。
Laravelで使用しているキャッシュ機構はRedisであり、Redisにはない型をLaravelから持たせると型変換を行った上でキャッシュに保持するためその分タイムロスが生まれる。
下記のような流れである。
Laravel Eloquentモデル
↓
jsonエンコード
↓
Redis
対してキャッシュから取得する際は逆の手順を踏む。
Redis
↓
jsonデコード
↓
Laravel Eloquentモデル
このように余分な型変換があるため処理時間が遅くなる。
ここを改善した結果、90分→60分の短縮に成功した。
以上のことから一概にDBへのアクセス数を減らすことが速度向上に繋がるとは限らない。
まとめ
今回私が試したチューニングが必ずしも正解ではないのでご留意ください。
環境やデータの持ち方によって対応する方法は数え切れないほどあるかと思います。
今回あげた例以外にも、無駄なループを減らしたり効率のいいプログラムの組み方をするなど基本的なものもあると思うので、色んな対応を模索してみてください。
Discussion