70万行くらいのMYSQLテーブルでSQL_CALC_FOUND_ROWSをやめたら高速化できた話
ある事案で、70万行くらいあるMYSQLの一覧テーブルの取得クエリを発行する際に、省エネだからと思ってSQL_CALC_FOUND_ROWSを使っていたら劇遅だったので、やめたら高速化できたという話です。
公開日:2019年9月4日
テーブル情報
- MYSQL:ver 5.6.42
- カラム数:14列
- データ数:おおよそ70万行
- インデックス:クエリに対しては適切に張っているつもり
改善前
SELECT SQL_CALC_FOUND_ROWS セレクト条件 FROM 色々JOIN WHERE インデクスの効く条件 LIMIT 0 30;
SELECT FOUND_ROWS() as count;
という感じでした。
この元々のクエリは、結果が多い場合だと1秒前後かかっていて、なんでそんなに重いんだろうと思っていました。
ちなみに、JOINは結構していますが、それぞれがしっかりとINDEXかPRIMARYで効くようにしているので、そこは原因ではないことは確認済み。
試しに、SQL_CALC_FOUND_ROWSをのぞいて、
SELECT セレクト条件 FROM 色々JOIN WHERE インデクスの効くと条件 LIMIT 0 30;
とすると、0.01秒くらいで結果が帰って来ます。
ここから「SQL_CALC_FOUND_ROWS」が重いのではないかと推測しました。
調べてみると、「SQL_CALC_FOUND_ROWS」は件数の大きいテーブルになるとパフォーマンスが落ちるという記事も見かけました。
改善後
「SQL_CALC_FOUND_ROWS」は、クエリ発行が楽なのはいいのですが、ユーザーへの応答が遅かったり無駄にDBに負荷をかけたりするのは無意味なので、「SQL_CALC_FOUND_ROWS」を無くして、同じ条件でcountするクエリを発行するようにしました。
SELECT SQL_CALC_FOUND_ROWS セレクト条件 FROM hoge 色々JOIN WHERE インデクスの効く条件 LIMIT 0 30;
SELECT count(id) as count FROM hoge WHERE インデクスの効く条件;
JOINは一覧への付加情報だったので、countの方ではのぞいています。
結果、APIからのコールで2秒くらいかかっていたのが、0.5秒まで高速化することができました。
全てのケースで「SQL_CALC_FOUND_ROWS」が悪という訳ではないですが、今回の自分のケースでは「SQL_CALC_FOUND_ROWS」を外すことで高速ができました。
データベースはテーブル構成や呼び出し方、データの量など様々な状況で変わってくるので、都度テストですね。
新着ノート
-
Gitlabの2段階認証下でコンテナレジストリにPushする方法
gitlab
公開日:2020年12月23日
-
HUGO
公開日:2020年4月27日
新着コード
-
cURLでCloudflare APIでキャッシュを削除する
cloudflare
公開日:2020年5月1日
-
iOS Safariでselectを含む要素にoverflow-y:scrollすると横にスクロールする時の対応
iOS
公開日:2020年4月15日