web-dev-qa-db-ja.com

COUNT(*)対COUNT(1)対COUNT(pk):どちらが良いですか?

私はしばしばこれらの3つのバリアントを見つけます:

SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;

私が見る限り、それらはすべて同じことを行い、私は自分のコードベースで3つを使用していることに気付きます。ただし、同じことを異なる方法で行うのは好きではありません。どちらに固執すべきですか?それらのいずれかが他の2つよりも優れていますか?

210
zneak

ボトムライン

COUNT(field)またはCOUNT(*)のいずれかを使用し、一貫して使用します。データベースでCOUNT(tableHere)またはCOUNT(tableHere.*)が許可されている場合は、それを使用します。

要するに、COUNT(1)を何にも使用しないでください。それはワントリックポニーで、あなたが望むものをめったに行いません、そしてそれらのまれなケースではcount(*)と同等です

カウントにcount(*)を使用

結合を含め、すべてをカウントする必要があるすべてのクエリに*を使用し、*を使用します

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

ただし、LEFT結合にはCOUNT(*)を使用しないでください。下位テーブルが親テーブルの何とも一致しない場合でも1を返すためです。

SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

COUNTで*を使用する場合、*が遅いと言ってテーブルから行全体をフェッチすることを勧める人にだまされないでください。 SELECT COUNT(*)*上のSELECT *は互いに関係がなく、まったく異なるものであり、共通のトークン、つまり*を共有するだけです。

代替構文

実際、テーブル名と同じようにフィールドに名前を付けることが許可されていない場合、RDBMS言語デザイナーはCOUNT(tableNameHere)COUNT(*)と同じセマンティクスを与えることができます。例:

行をカウントするために、次のことができます。

SELECT COUNT(emp) FROM emp

そして、彼らはそれをより簡単にすることができます:

SELECT COUNT() FROM emp

LEFT JOINの場合、次のようになります。

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

ただし、SQL標準ではテーブル名と同じ名前のフィールドに名前を付けることが許可されているため、それらはできません(COUNT(tableNameHere))。

CREATE TABLE fruit -- ORM-friendly name
(
fruit_id int NOT NULL,
fruit varchar(50), /* same name as table name, 
                and let's say, someone forgot to put NOT NULL */
shape varchar(50) NOT NULL,
color varchar(50) NOT NULL
)

Nullでカウント

また、フィールド名がテーブル名と一致する場合、フィールドをNULL可能にすることは推奨されません。 fruitフィールドに 'Banana'、 'Apple'、NULL、 'Pears'の値があるとします。これはすべての行をカウントするわけではなく、4ではなく3だけを生成します

SELECT count(fruit) FROM fruit

一部のRDBMSはそのような原則を実行しますが(テーブルの行をカウントするために、COUNTのパラメーターとしてテーブル名を受け入れます)、これはPostgresqlで機能します(以下の2つのテーブルのいずれにもsubordinateフィールドがない場合、フィールド名とテーブル名の間に名前の競合がない限り):

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

しかし、テーブルにsubordinateフィールドを追加すると、テーブルの行ではなくフィールド(null可能)をカウントするため、後で混乱を引き起こす可能性があります。

安全のために、以下を使用します。

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

count(1):ワントリックポニー

特にCOUNT(1)には、one-trickポニーであり、1つのテーブルクエリでのみ機能します。

SELECT COUNT(1) FROM tbl

ただし、結合を使用する場合、セマンティクスが混乱しない限り、このトリックはマルチテーブルクエリでは機能せず、特に次のように書くことはできません。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

COUNT(1)の意味は何ですか?

SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

これですか...?

-- counting all the subordinates only
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

それとも...?

-- or is that COUNT(1) will also count 1 for boss regardless if boss has a subordinate
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

慎重に考えれば、結合のタイプに関係なく、COUNT(1)COUNT(*)と同じであると推測できます。ただし、LEFT JOINの結果については、COUNT(1)を次のように機能させることはできません:COUNT(subordinate.boss_id)COUNT(subordinate.*)

したがって、次のいずれかを使用します。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Postgresqlで動作します。セットのカーディナリティをカウントしたいのは明らかです。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

セットのカーディナリティをカウントする別の方法は、非常に英語に似ています(テーブル名と同じ名前の列を作成しないでください): http://www.sqlfiddle.com/#!1/ 98515/7

select boss.boss_name, count(subordinate)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

これはできません: http://www.sqlfiddle.com/#!1/98515/8

select boss.boss_name, count(subordinate.1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

これを行うことはできますが、これにより誤った結果が生成されます。 http://www.sqlfiddle.com/#!1/98515/9

select boss.boss_name, count(1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
210
Michael Buen

それらの2つは常に同じ答えを生成します。

  • COUNT(*)は行数をカウントします
  • COUNT(1)は行数もカウントします

pkが主キーであり、値にnullが許可されていないと仮定すると、

  • COUNT(pk)は行数もカウントします

ただし、pkがnull以外に制約されていない場合は、別の答えが生成されます。

  • COUNT(possibly_null)は、列possibly_nullにNULL以外の値がある行の数をカウントします。

  • COUNT(DISTINCT pk)は、行の数もカウントします(主キーは重複を許可しないため)。

  • COUNT(DISTINCT possibly_null_or_dup)は、列possibly_null_or_dupの個別の非NULL値の数をカウントします。

  • COUNT(DISTINCT possibly_duplicated)は、possibly_duplicated句が列にある場合に、列NOT NULLの個別の(必然的にnullでない)値の数をカウントします。

通常、私はCOUNT(*);と書きます。これは、SQLの元の推奨表記法です。同様に、EXISTS節では、元の推奨表記であるため、通常WHERE EXISTS(SELECT * FROM ...)と記述します。代替案にメリットはありません。オプティマイザは、より不明瞭な表記を確認する必要があります。

49

これは、使用しているデータベースのタイプと、場合によってはテーブルのタイプによって異なります。

たとえば、MySQLを使用すると、count(*)はMyISAMテーブルでは高速になりますが、InnoDBでは低速になります。 InnoDBでは、count(1)またはcount(pk)を使用する必要があります。

9
Jarod Elliott

前に尋ねられて答えられた...

オンラインの書籍 は「COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )」と言います

「1」は非ヌル式なので、COUNT(*)と同じです。オプティマイザーはそれをtrivialとして認識するため、同じプランを提供します。 PKは一意であり、(少なくともSQL Serverでは)NULLではないため、COUNT(PK) = COUNT(*)

これはEXISTS (SELECT * ...またはEXISTS (SELECT 1 ...と似た神話です

ANSI 92仕様 、セクション6.5、一般規則、ケース1を参照してください

        a) If COUNT(*) is specified, then the result is the cardinality
          of T.

        b) Otherwise, let TX be the single-column table that is the
          result of applying the <value expression> to each row of T
          and eliminating null values. If one or more null values are
          eliminated, then a completion condition is raised: warning-
          null value eliminated in set function.
6
gbn

少なくともOracleでは、すべて同じです。 http://www.oracledba.co.uk/tips/count_speed.htm

5
ZeissS