« mylo(マイロ)が欲しい! | メイン | 第20回参議院議員通常選挙 »
2007年07月29日
COUNT(*) の代わりに FOUND_ROWS() を利用する
MySQL データベースからデータを取得するとき、オフセット(LIMIT)を利用する場合が多いと思う。同時に、条件に合致するデータの件数を知りたい場合も多いだろう。そのような時、そのようなクエリを投げれば良いのだろうか?
・データ取得
SELECT * FROM table WHERE field = 5 LIMIT 0, 10
・件数取得
SELECT COUNT(*) FROM table WHERE field = 5;
LIMIT を利用してデータを取得した後、別途 COUNT() 関数を利用したクエリを投げる事により、合致するデータの件数を知ることが出来る。このような単純なクエリの場合、各句をそれぞれ変数に格納していれば、特に件数取得用のクエリ文生成が面倒になることは無いだろう。
$select_data = 'SELECT '. ' * '; $select_count = 'SELECT '. ' (*) '; $from = 'FROM '. ' table '; $where = 'WHERE '. ' field = 5 '; $limit = 'LIMIT 0, 5 '; $sql_data = $select_data . $from . $where . $limit; $sql_count = $select_count . $from . $where;
単純なクエリの場合は、この方法でも良いのだが、複雑になったらどうだろうか?
・データ取得
SELECT COUNT(*), field2 FROM table WHERE field1 = 5 GROUP BY field2 LIMIT 0, 10
・件数取得
SELECT COUNT(DISTINCT field2) FROM table WHERE field1 = 5
GROUP BY 句がデータ取得のクエリ文に入る場合、前記のように各句を変数に格納していても、単純に件数取得用のクエリ文を生成することが出来ない。なぜなら、件数をカウントする COUNT(*) が GROUP BY でまとめた結果をカウントしてしまうからだ。正常にカウントするためには、GROUP BY を外す必要があり、データ取得用のクエリ文と、件数取得用のクエリ文は大きく異なる事になる。これでは、保守性が非常に悪い。今回の場合は DISTINCT 関数を用いれば解決できるが、複数のテーブルを結合したり HAVING が含まれたりする場合は、そう単純じゃない(はず)。
MySQL 4 から、新たに FOUND_ROWS() という関数が追加された。この関数を利用すると、簡単に合致するデータの件数を取得することが出来る。
・データ取得
SELECT SQL_CALC_FOUND_ROWS COUNT(*), field2 FROM table WHERE field1 = 5 GROUP BY field2 LIMIT 0, 10
・件数取得
SELECT FOUND_ROWS();
データ取得用のクエリ文に SQL_CALC_FOUND_ROWS を付加していれば、次のクエリ文で FOUND_ROWS を呼び出すだけで、合致する件数を取得することが出来る。
SELECT SQL_CALC_FOUND_ROWS を使用している場合、MySQL は完全な結果セットにいくつ行があるか計算する必要があります。しかし、結果セットをクライアントに送る必要がないため、LIMIT なしでクエリを再度実行するより速く行えます。
結果セットを送る必要の無い COUNT() との比較については、リファレンスマニュアルには書かれていない。しかし、オープンソース情報データベース OSS iPedia での検証によれば、約 70% のパフォーマンス向上が確認できたとの事(InnoDB によるものなので MyISAM は未検証)。
検索エンジンの類を MySQL で開発している場合、この FOUND_ROWS, SQL_CALC_FOUND_ROWS の利用は必須であろう。クエリのキャッシュ(SQL_CACHE)を利用している場合も、正常に作動する。
ま。アプリケーションから MySQL にアクセスする際に、クエリ文をべた書きしているケースは少なくなってきていると思うけど。僕は、未だに DBI を利用して、べた書き…。
【関連情報】
・11.10.3. 情報関数 - MySQL 5.1 リファレンスマニュアル
http://dev.mysql.com/doc/refman/5.1/ja/information-functions.html
・4.13.1. クエリ キャッシュの動作 - MySQL 5.1 リファレンスマニュアル
http://dev.mysql.com/doc/refman/5.1/ja/query-cache-how.html
・MySQL 行カウント SQL_CALC_FOUND_ROWS の効果 - OSS iPedia
http://ossipedia.ipa.go.jp/capacity/EV0603280115/
2007年07月29日 17:05 | Programming
トラックバック
コメント
貴重な情報ありがとうございます。
非常に参考になりました。
ちなみにですが、最後のデータ取得のSQLは、
SELECT SQL_CALC_FOUND_ROWS
COUNT(*), field2
FROM・・・
ではなく、
SELECT SQL_CALC_FOUND_ROWS
field2
FROM・・・
だけでよいと思うのですが。
前者だと最後の結果セット
SELECT
FOUND_ROWS();
が1になってしまうと思うのですが。
投稿者 igreks : 2012年02月28日 21:16