75

次のようなクエリを実行するのは一般的に悪い考えであることはわかっています。

SELECT * FROM `group_relations`

ただし、カウントだけが必要な場合は、このクエリを使用する必要があります。これにより、テーブルを変更できますが、同じ結果が得られるためです。

SELECT COUNT(*) FROM `group_relations`

またはより具体的に

SELECT COUNT(`group_id`) FROM `group_relations`

後者の方が高速になる可能性があると感じていますが、他に考慮すべき点はありますか?

更新: この場合、私は InnoDB を使用しています。具体的でなくて申し訳ありません。

4

14 に答える 14

108

問題の列が NOT NULL の場合、両方のクエリは同等です。group_id に null 値が含まれている場合、

select count(*)

すべての行をカウントしますが、

select count(group_id)

group_id が null でない行のみをカウントします。

また、MySQL などの一部のデータベース システムでは、count(*) を要求するときに最適化を採用しているため、そのようなクエリは特定のクエリよりも少し高速になります。

個人的には、カウントするだけの場合は、null を安全に使用するために count(*) を実行しています。

于 2009-01-19T11:12:40.183 に答える
22

私の記憶が正しければ、MYSQL では COUNT(*) はすべての行をカウントしますが、COUNT(column_name) は指定された列に NULL 以外の値を持つ行のみをカウントします。

于 2009-01-19T11:10:50.950 に答える
11

COUNT(*) はすべての行をカウントしますが、COUNT(column_name) は指定された列に NULL 値のない行のみをカウントします。

MySQL で注意すべき重要事項:

COUNT() は、行カウントがキャッシュされるため、* または非 null 列の MyISAM テーブルで非常に高速です。InnoDB には行数のキャッシュがないため、列が null になるかどうかに関係なく、COUNT(*) または COUNT(column_name) のパフォーマンスに違いはありません。相違点の詳細については、MySQL パフォーマンス ブログのこの投稿を参照してください。

于 2009-01-19T11:32:24.650 に答える
7

group_relationsを試すとSELECT COUNT(1) FROM、列から情報を取得しようとしないため、少し速くなります。

編集:私はいくつかの調査を行ったところ、これは一部のデータベースでのみ発生することがわかりました。sqlserver では 1 または * を使用するのは同じですが、oracle では 1 を使用する方が高速です。

http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/9367c580-087a-4fc1-bf88-91a51a4ee018/

どうやらmysqlにはそれらの間に違いはありません.sqlserverのように、パーサーはクエリをselect(1)に変更するようです。誤解を招いたら申し訳ありません。

于 2009-01-19T11:14:41.317 に答える
5

私自身、これが気になりました。ドキュメントと理論的な答えを読むのは問題ありませんが、私はそれらと経験的な証拠とのバランスを取るのが好きです.

5,607,997 レコードを含む MySQL テーブル (InnoDB) があります。テーブルは私用のプライベート サンドボックスにあるため、コンテンツが静的であり、他の誰もサーバーを使用していないことがわかっています。これにより、パフォーマンスへの外部からの影響がすべて効果的に取り除かれると思います。where 句のテスト (WHERE Id IS NOT NULL) に使用する、決して null にならないことがわかっている auto_increment 主キー フィールド (Id) を持つテーブルがあります。

テストの実行中に他に考えられる唯一の不具合は、キャッシュです。初めてクエリを実行すると、同じインデックスを使用する後続のクエリよりも常に遅くなります。以下では、これをキャッシュ シード呼び出しと呼びます。少し混乱させるために、データに関係なく常にtrueと評価されることがわかっているwhere句を使用して実行しました(TRUE = TRUE)。

ここに私の結果があります:

クエリの種類

      |  w/o WHERE          | where id is not null |  where true=true

カウント()

      |  9 min 30.13 sec ++ | 6 min 16.68 sec ++   | 2 min 21.80 sec ++
      |  6 min 13.34 sec    | 1 min 36.02 sec      | 2 min 0.11 sec 
      |  6 min 10.06 se     | 1 min 33.47 sec      | 1 min 50.54 sec

COUNT(ID)

      |  5 min 59.87 sec    | 1 min 34.47 sec      | 2 min 3.96 sec 
      |  5 min 44.95 sec    | 1 min 13.09 sec      | 2 min 6.48 sec

カウント(1)

      | 6 min 49.64 sec    | 2 min 0.80 sec       | 2 min 11.64 sec
      | 6 min 31.64 sec    | 1 min 41.19 sec      | 1 min 43.51 sec

++これは、キャッシュの Seeding 呼び出しと見なされます。他のものよりも遅くなることが予想されます。

結果がすべてを物語っていると思います。COUNT(Id) は、通常、他よりも優れています。Where 句を追加すると、true と評価されることがわかっている句であっても、アクセス時間が大幅に短縮されます。スイート スポットは COUNT(Id)... WHERE Id IS NOT NULL のようです。

おそらく、より小さなテーブルや、カウントしているフィールドとは異なるフィールドに対する where 句を使用して、他の人々の結果を確認したいと思います。私が考慮していない他のバリエーションがあると確信しています。

于 2009-03-19T21:36:00.463 に答える
4

代替案を探す

これまで見てきたように、テーブルが大きくなると、COUNTクエリが遅くなります。最も重要なことは、あなたが解決しようとしている問題の性質を考慮することだと思います。たとえば、多くの開発者COUNTは、結果セットの総ページ数を決定するために、大量のレコードセットのページネーションを生成するときにクエリを使用します。

クエリの速度が遅くなることを知っているのでCOUNT、遅いクエリを回避するだけのページネーションコントロールを表示する別の方法を検討できます。Googleのページ付けは優れた例です。

非正規化

特定のカウントに一致するレコードの数を絶対に知る必要がある場合は、データの非正規化の古典的な手法を検討してください。ルックアップ時に行数をカウントする代わりに、レコードの挿入時にカウンターをインクリメントし、レコードの削除時にそのカウンターをデクリメントすることを検討してください。

これを行うことにした場合は、べき等のトランザクション操作を使用して、これらの非正規化された値の同期を維持することを検討してください。

BEGIN TRANSACTION;
INSERT INTO  `group_relations` (`group_id`) VALUES (1);
UPDATE `group_relations_count` SET `count` = `count` + 1;
COMMIT;

または、RDBMSがデータベーストリガーをサポートしている場合は、データベーストリガーを使用できます。

アーキテクチャによっては、memcachedなどのキャッシュレイヤーを使用して、非正規化された値を保存、インクリメント、デクリメントし、キャッシュキーがない場合は、低速のCOUNTクエリに単純にフォールスルーすることが理にかなっている場合があります。これにより、非常に揮発性の高いデータがある場合に全体的な書き込み競合を減らすことができますが、このような場合は、ドッグパイル効果の解決策を検討する必要があります。

于 2009-07-08T06:40:54.680 に答える
2

主キーなどのインデックス付きの列でカウントすることをお勧めします。

SELECT COUNT(`group_id`) FROM `group_relations`
于 2009-06-22T22:49:55.240 に答える
2

COUNT のアスタリスクは、テーブルのすべてのフィールドを選択するためのアスタリスクとは関係ありません。COUNT(*) が COUNT(field) よりも遅いと言うのはまったくのゴミです。

select COUNT(*) は select COUNT(field) よりも高速であることがわかります。RDBMS は、フィールドの代わりに COUNT に "*" を指定したことを検出した場合、カウントをインクリメントするために何も評価する必要はありません。一方、COUNT でフィールドを指定すると、RDBMS は常にフィールドが null かカウントしないかを評価します。

ただし、フィールドが null 許容の場合は、COUNT でフィールドを指定します。

于 2009-01-19T12:00:07.480 に答える
2

COUNT(*) 個の事実と神話:

神話: 「InnoDB は count(*) クエリをうまく処理できない」:

ほとんどの count(*) クエリは、WHERE 句がある場合、すべてのストレージ エンジンで同じ方法で実行されます。それ以外の場合、InnoDB はフル テーブル スキャンを実行する必要があります。

FACT : InnoDB は、where 句がないと count(*) クエリを最適化しません

于 2009-03-09T20:56:11.173 に答える
2

MySQL ISAM テーブルは、フル テーブル スキャンをスキップして、COUNT(*) を最適化する必要があります。

于 2009-01-19T11:39:31.860 に答える
1

セバスチャンがすでに言ったように、実際に達成しようとしていることに依存する必要があります。つまり、意図を明確にしてください。行をカウントするだけの場合COUNT(*) を使用するか、単一の列をカウントする場合は COUNT(column) を使用します。

DBベンダーもチェックする価値があるかもしれません。Informix を使用していたときは、COUNT(*) の最適化があり、1 つまたは複数の列をカウントする場合と比較して、クエリ プランの実行コストが 1 であったため、より高い数値が得られました。

于 2009-01-19T11:14:51.003 に答える
1

SELECT COUNT(1) FROM group_relations を試すと、列から情報を取得しようとしないため、少し速くなります。

COUNT(1) は以前は COUNT(*) よりも高速でしたが、現在の DBMS は列について知りたくないことを十分に認識できるほどスマートであるため、もはやそうではありません。

于 2009-01-19T11:44:07.717 に答える
0

次のようなクエリを実行するのは一般的に悪い考えであることはわかっています。

SELECT * FROM `group_relations`

ただし、カウントだけが必要な場合は、このクエリを使用する必要があります。これにより、テーブルを変更できますが、同じ結果が得られるためです。

SELECT COUNT(*) FROM `group_relations`

あなたの質問が示唆するようSELECT *に、テーブルを変更するとコードの変更が必要になる可能性があるため、その理由は賢明ではありません。には当てはまりませんCOUNT(*)。特殊な動作が必要になることはほとんどありSELECT COUNT('group_id')ません。通常、レコードの数を知りたい場合です。そのためのものCOUNT(*)ですので、ご利用ください。

于 2009-06-22T23:01:59.943 に答える