MySQL:行数をカウントする最速の方法


117

MySQLでは、行数をカウントするためにどちらが高速なのでしょうか。

この:

SELECT COUNT(*) FROM ... WHERE ...

または、代替:

SELECT 1 FROM ... WHERE ...

// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

これは明らかにデータベースの領域であり、このようなことを内部で決定する場合、データベースエンジンは他の誰よりも高速であるべきであるため、最初の方法の方が高速であると考えられます。


1
ああ、私は同様の質問を見つけました(stackoverflow.com/questions/1855226/…)。しかし、私は使用しSELECT 1、使用しませんSELECT *。違いはありますか?
フランツ、

私にはわかりませんが、これら2つの答えは同じであると考えられます。mysqlクエリオプティマイザはそれぞれに対して同じことを行う可能性があります。前者は後者ほど曖昧さは少ないと述べた。ベンチマークを書いてテストしてみませんか?
Jesse Cohen

ええと、私は別の言葉で同様の質問をすることでSOの検索エンジンの可視性を高めようとしているとしましょう;)
Franz

1
違いは、PHP側に送信されるデータの量です。列数が多いほど、SELECT 1に比べてSELECT *の取得が遅くなります。これは、数値1だけでなくすべての列が取得されるためです。mysql_query()たとえば、を実行すると、結果セット全体がMySQLからPHPに送信されます。そのデータで行います。
toon81

このような質問をすることは、洞察や新しいアイデアを得るための優れた方法ですが、最終的には、実際に速度を上げたい特定のシナリオがある場合は、テストを実行して最速のものを確認する必要があります。
still_dreaming_1

回答:


124

あなたは、ときにCOUNT(*)それが最良の結果となりますので、それは、カウント列インデックスになります。でMySQL のMyISAMエンジンは、実際に行数を格納し、それはあなたがすべての行をカウントしようとするたびに、すべての行をカウントdoensn't。(主キーの列に基づく)

PHPを使用して行をカウントすることは、mysqlからphpにデータを送信する必要があるため、あまり賢くありません。mysql側で同じことを達成できるのになぜそれをするのですか?

COUNT(*)が遅い場合はEXPLAIN、クエリを実行して、インデックスが実際に使用されているかどうか、およびインデックスをどこに追加するかを確認してください。


以下は最速の方法ではありCOUNT(*)ませんが、実際には適合しない場合があります-結果のグループ化を開始すると、COUNT実際にはすべての行をカウントしない問題に遭遇する可能性があります。

解決策はSQL_CALC_FOUND_ROWSです。これは通常、行を選択するときに使用されますが、(ページングなどのために)行の総数を知る必要があります。データ行を選択するときはSQL_CALC_FOUND_ROWS、SELECTの後にキーワードを追加するだけです。

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

必要な行を選択したら、次の1つのクエリでカウントを取得できます。

SELECT FOUND_ROWS();

FOUND_ROWS() データ選択クエリの直後に呼び出す必要があります。


結論として、すべては実際にはエントリの数とWHEREステートメントの内容によって決まります。多くの行(数万、数百万、およびそれ以上)がある場合は、インデックスの使用方法に注意を払う必要があります。


14
修正:MyISAM行数を格納します。などの他のストレージエンジンInnoDB 行カウントを保存せず、毎回すべての行をカウントします
スクラムマイスター

1
行があるかどうかを単に確認したい場合、どちらが最も高速かわかりますSELECT 1 FROM ... LIMIT 1SELECT COUNT(*) FROM ...
フランツ

1
とにかくデータが必要で、ページ分割などのカウントのみが必要な場合は、注意することはおそらく役に立ちます。データを取得してからプログラムの行数をカウントする方が効率的です。
Tyzoid 2013

6
エンジンが行数を格納するかどうかは関係ありません。質問は明確にWHERE条項があると述べています。
アルバロゴンサレス

1
@Franz SELECT COUNT(*) FROM ...は、何をスキャンする必要があるかによって(たとえば、数百万/数十億/数兆行の非常に大きなテーブルまたはインデックス)、かなりの時間がかかる場合があります。 SELECT 1 FROM ... LIMIT 1最初の行に制限しているため、すぐに戻ります。
jbo5112 2014

59

私のチームメイトと話した後、リカルドはより速い方法は次のとおりであると私たちに言いました

show table status like '<TABLE NAME>' \G

ただし、結果が正確でない可能性があることを覚えておく必要があります。

コマンドラインからも使用できます:

$ mysqlshow --status <DATABASE> <TABLE NAME>

詳細:http : //dev.mysql.com/doc/refman/5.7/en/show-table-status.html

そして、mysqlperformanceblogで完全な議論を見つけることができます


2
InnoDBの場合、これは概算です。
Martin Tournoij、2014

2
これは、count(*)が文字どおり数時間かかる非常に大きなテーブルの行数の大まかなアイデアが必要な場合に知っておくと便利です。
Mark Hansen

これにより、髪の毛をすべて抜く手間が省けました。COUNT(*)は、データベース内のすべての3300万行をカウントするのに時間がかかりました。とにかく、並列化された行削除機能が機能しているかどうかを知りたかっただけです。正確な番号は必要ありませんでした。
joemar.ct 2015年

1
+1テーブルステータスの代わりに「COUNT(*)」を使用することは、「正確さ」ではなく「最速」についてであるように、この質問に対する正しい答えであるべきです。
lepe

2
使用するSHOW TABLE STATUS(または同等SELECTではinformation_schema)速いですが、それは処理しませんWHERE句を。MyISAMの場合は正確ですが、InnoDBの場合は不正確(2倍になる場合もあります)です。
リックジェームズ

29

すばらしい質問、すばらしい答え。誰かがこのページを読んでいてその部分を見逃している場合に、結果をエコーする簡単な方法を次に示します。

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");

5
mysql_queryは、PHP 5.5.0以降では非推奨の関数です。
Omar Tariq 2016

8
なんでas countid一見すると混乱しています。
Orkhan Alikhanov

質問に答えません
メンタル的な

17

このクエリ(bayuahが投稿したものにています)は、データベース内のすべてのテーブル数のすばらしい要約を示しています(Ivan Cachicatariによるストアドプロシージャの簡略版)。

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE'; 

例:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |

結果が出ます。しかし、count(1)とこれの結果は異なります。この方法では、countクエリより常に少ない数が得られます。何かご意見は?
Ayyappan Sekar 2018年

3
読者への単なるメモ。この方法は非常に高速ですが、InnoDBが使用さinformation_schemaSELECT count(*) FROMている場合に格納される値はによって返される値とは異なるため、概算の行数で作業できる場合にのみ適用できます。厳密な値が必要な場合、このメソッドはMyISAMテーブルでのみ厳密な値を与えることに注意してください。InnoDBでは、行数はおおよその数です。
Bartosz Firyn

13

以下が最も速い応答時間を提供することを常に理解しています。

SELECT COUNT(1) FROM ... WHERE ...

1
SELECT 1 FROM ... WHERE ...がさらに高速にならないでしょうか?
パトリック14

3
@patrick- SELECT 1 ...と同じ数の行を返しWHERELIMIT要求すると、それらはすべて「1」になります。
リックジェームズ

1
show table status like '<TABLE NAME>' これははるかに速くなります。
深い

@deep- WHERE節がある場合は関係ありません。そして、InnoDBの場合、それは推定値にすぎません。
リックジェームズ

@RickJamesはいtrue!
深い

6

結果セット全体の数を取得する必要がある場合は、次のアプローチをとることができます。

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

これは通常は使用よりも速くはCOUNTありませんが、内部で計算を行っており、ユーザーにデータを返送しないため、パフォーマンスの向上が疑われます。

これら2つのクエリを実行することは、合計を取得するためのページ分割には適していますが、特にWHERE句の使用には適していません。


興味深い。最も一般的なデータベースシステム全体で機能しますか?MySQL、Postgres、SQLite ...?
フランツ

4
多くの場合、これは実際にはCOUNT(*)を使用するよりも速くありません。stackoverflow.com/questions/186588/…を
toon81

2
この関数を使用するときは、非常に注意する必要があります。その無謀な使用は、かつて私たちの生産環境全体を粉砕しました。これは非常にリソースを集中的に使用するため、注意して使用してください。
Janis Peisenieks 2013

6

COUNT(*)vs の実行時間を比較するためにいくつかのベンチマークを行いましたCOUNT(id)(idはテーブルの主キー-インデックス付きです)。

試行回数:10 * 1000クエリ

結果: COUNT(*)7%高速

グラフを表示:ベンチマークグラフ

私のアドバイスは以下を使用することです: SELECT COUNT(*) FROM table


1
FYIとカウントする一般的な方法もありますCOUNT(1)が、いくつかのベンチマークを見て興味深いものになるだろうが、...
SLIQ

4

これを試して:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

@lepeごめんなさい。つまり、反対票を投じた人がなぜ彼/彼女がそれをするのかについて何らかの説明をするのは本当に素晴らしいので、誰もがそれについて何かを学ぶことができます。
bayuah

1
これにより、おおよその答えがすぐに得られます。正確な答えが必要な場合はselect count(*) from table_name、何かを実行する必要があります。dba.stackexchange.com/questions/151769/...
Programster

@Programsterありがとうございます。暗闇に1年近くいるよりはましだ。
bayuah 2016年

1
@bayuah最後のコメントで何を意味するのかわかりません。私はあなたの答えに反対票を投じたのは私だとあなたが思うだけです。私はそうではありません。
Programster

1
@Programsterいいえ、申し訳ありませんが、そういう意味ではありませんでした。私はあなたの説明に感謝するつもりだったので、ダウンボーターが彼/彼女がそれをしたときに多分考えたことを推測することができます。
バユア

3

おそらく、の実行を検討する必要があるかもしれませんSELECT max(Id) - min(Id) + 1。これは、IDがシーケンシャルで、行が削除されていない場合にのみ機能します。ただし、非常に高速です。


3
注意:サーバーは自動増分値> 1(バックアップ上の理由から)を使用する場合があるため、このソリューションは適切ですが、最初にDB構成を確認する必要があります。
Alex

1

EXPLAIN SELECT id FROM ....私のためにトリックをしました。rows結果の列の下の行数がわかりました。


0

私はドイツ政府のテーブルを扱い、時には6,000万件のレコードがありました。

そして、総行数を何倍も知る必要がありました。

したがって、データベースプログラマーは、すべてのテーブルが常に1つのレコードであり、合計レコード数が格納されるレコードであると判断しました。INSERTまたはDELETE行に応じて、この数を更新しました。

他のすべての方法を試しました。これは断然最速の方法です。


1
そして、その行を更新した方法の詳細は何ですか?これは、テーブルの設計が不完全であることを意味します。この場合、すべての行で、乗車のために無駄な整数が必要になります。
2016年

5
ええ、それは本当に愚かな笑です。すべてのクエリで、最初の行を無視する必要があります。合計テーブルを作成して、トリガーに基づいてデータを入力するだけです。挿入時のユーザーテーブル、合計テーブルの更新。削除時のユーザーテーブル、合計テーブルの更新。
HTMLGuy 2017年

-1

主キーのwhere条件を含むcount(*)ステートメントは、全テーブルスキャンを回避するために行カウントをはるかに速く返しました。

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

これは私よりずっと速い

SELECT COUNT(*) FROM ...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.