121

MySQL クエリから結果の数を取得し、同時に結果を制限する方法があるかどうか疑問に思っていました。

ページネーションの仕組み(私が理解しているように)、最初に次のようなことをします

query = SELECT COUNT(*) FROM `table` WHERE `some_condition`

num_rows(query) を取得すると、結果の数が得られます。しかし、実際に結果を制限するには、次のような 2 番目のクエリを実行する必要があります。

query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10

私の質問:とにかく、与えられる結果の総数を取得し、単一のクエリで返される結果を制限する方法はありますか? または、これを行うより効率的な方法。ありがとう!

4

9 に答える 9

75

2 つのクエリを実行することはほとんどありません。

必要以上に 1 行だけ返して、ページに 10 行だけ表示し、表示されている行よりも多い場合は [次へ] ボタンを表示します。

SELECT x, y, z FROM `table` WHERE `some_condition` LIMIT 0, 11
// iterate through and display 10 rows.

// if there were 11 rows, display a "Next" button.

クエリは、最も関連性の高いものから順に返されます。おそらく、ほとんどの人は 412 ページ中 236 ページに行くことを気にしないでしょう。

Google 検索を行ったときに、結果が最初のページに表示されない場合、9 ページではなく 2 ページに移動する可能性があります。

于 2010-07-24T11:14:50.743 に答える
29

二重クエリを回避するもう 1 つの方法は、最初に LIMIT 句を使用して現在のページのすべての行をフェッチし、次に最大数の行が取得された場合にのみ 2 回目の COUNT(*) クエリを実行することです。

多くのアプリケーションでは、すべての結果が 1 ページに収まる可能性が高く、ページネーションを行う必要があるのは標準ではなく例外です。このような場合、最初のクエリは最大数の結果を取得しません。

たとえば、stackoverflow の質問に対する回答が 2 ページ目にはみ出すことはめったにありません。回答に対するコメントが、すべてを表示するために必要な 5 程度の制限を超えることはめったにありません。

したがって、これらのアプリケーションでは、最初に LIMIT を使用してクエリを実行するだけでよく、その制限に達しない限り、2 番目の COUNT(*) クエリを実行する必要なく、行数が正確にわかります。ほとんどの状況をカバーします。

于 2011-09-08T05:19:15.637 に答える
16

ほとんどの場合、直感に反するように見えますが、1 つのクエリで実行するよりも、2 つの個別のクエリで実行する方がはるかに高速で、リソースの消費も少なくなります。

SQL_CALC_FOUND_ROWS を使用すると、大きなテーブルの場合、最初に COUNT(*) を使用し、2 つ目に LIMIT を使用して 2 つのクエリを実行するよりも、クエリが大幅に遅くなります。これは、SQL_CALC_FOUND_ROWS によって LIMIT 句が行をフェッチする前ではなくに適用されるため、制限を適用する前にすべての可能な結果の行全体をフェッチするためです。これは、実際にデータをフェッチするため、インデックスでは満たすことができません。

2 つのクエリ アプローチを採用する場合、最初のクエリは COUNT(*) のみをフェッチし、実際には実際のデータをフェッチしない場合、通常はインデックスを使用でき、実際の行データをフェッチする必要がないため、これははるかに迅速に満たすことができます。それが見るすべての行。次に、2 番目のクエリは、最初の $offset+$limit 行を調べてから返すだけで済みます。

MySQL パフォーマンス ブログのこの投稿では、これについてさらに説明しています。

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

ページネーションの最適化の詳細については、この投稿この投稿を確認してください。

于 2009-05-04T03:46:54.207 に答える
2

私の答えは遅れるかもしれませんが、2番目のクエリ(制限付き)をスキップして、バックエンドスクリプトで情報をフィルタリングすることができます。たとえば、PHPでは、次のようなことができます。

if($queryResult > 0) {
   $counter = 0;
   foreach($queryResult AS $result) {
       if($counter >= $startAt AND $counter < $numOfRows) {
            //do what you want here
       }
   $counter++;
   }
}

しかしもちろん、考慮すべきレコードが何千もある場合、それは非常に速く非効率になります。事前に計算されたカウントを調べることをお勧めします。

これは主題に関する良い読み物です:http: //www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf

于 2012-04-09T05:42:56.670 に答える
2
query = SELECT col, col2, (SELECT COUNT(*) FROM `table`)/10 AS total FROM `table` WHERE `some_condition` LIMIT 0, 10

10 はページ サイズ、0 はページ番号です (クエリで pageNumber-1 を使用する必要があります)。

于 2009-05-04T02:21:22.680 に答える
-18
SELECT * 
FROM table 
WHERE some_condition 
ORDER BY RAND()
LIMIT 0, 10
于 2012-10-29T03:28:03.343 に答える