#はじめに
Laravel ✖️ Lambda ✖️ API Gateway ✖️ RDS MySQL
によるアプリケーションで、30万レコード以上あるテーブルを同じく3以上の他テーブルたち(それぞれ数万行ある)と結合して読み込む際に、処理速度のアップで四苦八苦したので記録として残します。
APIGateway を使っており、30秒以内にレスポンスを返す必要がありました。
バージョン
MySQL 5.7
調べてわかったこと試したこと
キーワード大文字小文字で処理速度が変わる?
少なくともMySQLでは変わりません。
この記事では変わると書かれてありますが。。これは他のDBエンジンのことだと思ってます。
Nested Loop Join を知る
2つのテーブルを結合させるときに使うJOIN
その際の結合方法が数種類あるらしいです。
処理速度を上げたいときに理解必須の仕組みです。
- merge join
- hash join
- nested loop join <--- MySQLは基本これ
MySQL 8.0.20 ではハッシュジョインが追加されたみたいですね。
n ✖️ m を最小値にする
要は、Nested Loop Join (NLJ)とは、結合されるたびにイテレートされるということ。
駆動表のレコード数(n)、内部表でマッチするのレコード数(m)
つまりJOINされると n ✖️ m 回内部的な処理が走ります。
mは条件次第(JOIN hoge
ON ここの記述
)で処理の事前にレコード数を減らせます。
この回数を小さくするには、n が小さくするもしくはnの処理を早くする必要があります。
インデックスを知る
私の場合はINDEXには大きな問題ないと判断したので、INDEXについて深掘りするのは省略しますが、
- 演算されたカラムのインデックスは働かない
- INDEX使うか使わないか、複数ある場合等、割とMySQLが判断している部分がある
等に注意しながら、SQL書きました。
どのカラムのINDEXが使われるかを調べるときに使うのが、後述にあるEXPLAINです。
Explainを知る
Explainとは
「MySQL EXPLAIN とは」で出てきた最初の記事を貼っておきます。
実行計画であり実行結果が必ずそうなるとは限らないということ
これといった具体例提示できませんが、一応これは忘れないようにします。
filtered
先述したindexの使い方がおそらく一番大事なのだとは思うが、今回私が特に大きく改善できたのはこの値
filtered
filteredは、検索条件によって絞り込まれるレコードの割合です。
explain したら出てくるカラムですが、この数値がかなり悪かった。
- 結合条件を増やす
- joinする順番を変える
を行って、filtered を100に近づけていきました。
キャッシュ
クエリキャッシュ
この記事見ていけるかもって思ったけど
MySQL 5.7から非推奨でしたので却下
https://qiita.com/tonyfactory/items/a00e4bf25b6a132dfce7
#おわりに
上記色々試してみて、確かに速度は上がりましたが、期待していたレベルまでは改善しませんでした。
あと試せるのは下記かなぁと
- 実行結果がそのまま格納されている別テーブルを作成する。レコードの追加や更新は、定時に自動でバッチ処理を走らせて更新する。
- Amazon ElastiCache などのキャッシュを上手く使う
どちらにしても今回のこの機能の使用頻度やテーブルの更新頻度等を鑑みる必要がありますね。
参考記事