web-dev-qa-db-ja.com

どちらが最速ですか? SELECT SQL_CALC_FOUND_ROWS FROM `table`、またはSELECT COUNT(*)

通常ページングで使用されるSQLクエリによって返される行の数を制限する場合、レコードの合計数を決定するには2つの方法があります。

方法1

元のSELECTSQL_CALC_FOUND_ROWSオプションを含め、SELECT FOUND_ROWS()を実行して行の総数を取得します。

SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();  

方法2

クエリを通常どおり実行し、SELECT COUNT(*)を実行して合計行数を取得します

SELECT * FROM table WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM table WHERE id > 100;  

どの方法が最良/最速ですか?

165
Jrgns

場合によります。このテーマに関するMySQL Performance Blogの投稿を参照してください: http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

簡単な要約:Peterは、インデックスやその他の要因に依存すると言います。投稿へのコメントの多くは、SQL_CALC_FOUND_ROWSが2つのクエリを実行するよりもほとんど常に遅く、時には最大10倍遅くなると言っているようです。

112
nathan

「最良の」アプローチを選択する場合、速度よりも重要な考慮事項は、コードの保守性と正確さです。その場合、単一のクエリのみを維持する必要があるため、SQL_CALC_FOUND_ROWSの使用をお勧めします。単一のクエリを使用すると、メインクエリとカウントクエリの微妙な違いが完全に排除され、COUNTが不正確になる可能性があります。

20
Jeff Clemens

次の記事によると: https://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

Where句にINDEXがある場合(ケースでidにインデックスが付けられている場合)、SQL_CALC_FOUND_ROWSを使用しない方が良い代わりに2つのクエリを使用しますが、where句(ケースのid)に入れるものにインデックスがない場合は、SQL_CALC_FOUND_ROWSを使用しますの方が効率的です。

13
patapouf_ai

私見、2つのクエリの理由

SELECT * FROM count_test WHERE b = 666 ORDER BY c LIMIT 5;
SELECT count(*) FROM count_test WHERE b = 666;

sQL_CALC_FOUND_ROWSを使用するよりも高速です

SELECT SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 555 ORDER BY c LIMIT 5;

特定のケースとして見られる必要があります。

実際には、ORDER + LIMITと同等の暗黙の選択性と比較したWHERE句の選択性に依存します。

Arvidsがコメント( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-1174394 )で言ったように、 EXPLAINの使用、またはテンポラリーテーブルの使用は、SCFRがより高速であるかどうかを知るための優れた基盤となるはずです。

しかし、追加したように( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-8166482 )、結果は本当に、実際にケースに依存します。特定のページネーターについては、「最初の3ページには2つのクエリを使用します。次のページでは、SCFRを使用します」!

不要なSQLをいくつか削除してからCOUNT(*)を実行すると、SQL_CALC_FOUND_ROWSよりも高速になります。例:

SELECT Person.Id, Person.Name, Job.Description, Card.Number
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
LEFT JOIN Card ON Card.Person_Id = Person.Id
WHERE Job.Name = 'WEB Developer'
ORDER BY Person.Name

次に、不要な部分なしでカウントします。

SELECT COUNT(*)
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
WHERE Job.Name = 'WEB Developer'
6
Jessé Catrinck

ベンチマークする他のオプションがあります。

1。)ウィンドウ関数は、実際のサイズを直接返します(MariaDBでテスト済み):

SELECT 
  `mytable`.*,
  COUNT(*) OVER() AS `total_count`
FROM `mytable`
ORDER BY `mycol`
LIMIT 10, 20

2。)箱から出して考えると、ほとんどの場合、ユーザーは正確なサイズを知る必要はありません表の場合、大体は十分であることがよくあります。

SELECT `TABLE_ROWS` AS `rows_approx`
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE `TABLE_SCHEMA` = DATABASE()
  AND `TABLE_TYPE` = "BASE TABLE"
  AND `TABLE_NAME` = ?
1
Code4R7