2022年6月19日日曜日

MariaDBやMySQLで少ない負荷で部分的な値の取得と合計数を取得したい場合はFOUND_ROWSが便利


背景

自分は今までDBから部分的なレコードと合計数を取得するのに、探査対象(where)が同じで出力数(limit)と出力項目(selectが*かCOUNT(*)か)が異なる処理をそれぞれ実行していました。
負荷が軽ければそれでも動くのですが、計算量が大きいと処理時間が無視できない長さになり、応答の遅さに影響します。

何とかならないかと調べたところMySQLではFOUND_ROWSという機能があり、それを使えば部分的なレコード取得時に合計数を別途格納し、合計数の取得は格納した数を呼び出す処理を実行すれば、whereが同じ処理を2回実行するのに比べてほぼ半分の時間で処理できると分かりました。

今後も使う気がするので、備忘録を兼ねて記事を残します。

使ったもの

MariaDB
FOUND_ROWSはMySQLでも使えます。

書き方: クエリへのSQL_CALC_FOUND_ROWSの追加とFOUND_ROWS()の実行

limit付きのクエリのselectにSQL_CALC_FOUND_ROWSを付けて実行します。
今回はraw_device_logテーブルに対してクエリを実行します。
select SQL_CALC_FOUND_ROWS * from raw_device_log limit 10;
実行したDBでは10レコードを0.004秒で取得できました。
10 rows in set (0.004 sec)

上記のクエリ実行後の同一トランザクションでFOUND_ROWS()の値を出力するクエリを実行します。
(jdbcを利用してクエリを実行する場合、with-db-transactionなどでトランザクションを維持します。)
select FOUND_ROWS();
+--------------+
| FOUND_ROWS() |
+--------------+
| 2146 |
+--------------+
1 row in set (0.000 sec)
格納している値の表示なので、処理時間ほぼ0で合計数を取得できました。

終わり

FOUND_ROWSの利用により、limit付きの部分的なレコード取得と合計数の取得をほぼ1つクエリの実行時間で行えました。

参考

FOUND_ROWS - MariaDB
FOUND_ROWS - MySQL8.0
LIMITで件数制限をしつつ、全件数を取得する方法 SQL_CALC_FOUND_ROWS FOUND_ROWS()
clj-server-practice/raw_device_log.clj#L173-L175

0 件のコメント :