我经常发现这三种变体:
SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;
据我所知,他们都做同样的事情,我发现自己在我的代码库中使用了三个。但是,我不喜欢以不同的方式做同样的事情。我应该坚持哪一个?他们中的任何一个比其他两个更好吗?
答案 0 :(得分:204)
使用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
但是不要将COUNT(*)
用于LEFT连接,因为即使从属表与父表中的任何内容都不匹配,它也将返回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
但他们不能这样做(COUNT(tableNameHere)
),因为SQL标准允许命名一个与其表名同名的字段:
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
)
而且,如果字段的名称与表名匹配,则使字段为空可能不是一个好习惯。假设你在fruit
字段上有'Banana','Apple',NULL,'Pears'的值。这不会计算所有行,它只会产生3,而不是4
SELECT count(fruit) FROM fruit
虽然有些RDBMS执行这种原则(用于计算表的行,它接受表名作为COUNT的参数),但这将在Postgresql中有效(如果下面两个表中的任何一个表中都没有subordinate
字段,即只要字段名和表名之间没有名称冲突):
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
但如果我们在表中添加subordinate
字段,那么可能会导致混淆,因为它会计算字段(可以为空),而不是表行。
为了安全起见,请使用:
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)
,它是一个一招小马,它仅适用于一个表查询:
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 JOINs结果,我们无法将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
答案 1 :(得分:48)
其中两个总能产生相同的答案:
COUNT(*)
计算行数COUNT(1)
也会计算行数假设pk
是主键,并且值中不允许空值,则
COUNT(pk)
也会计算行数但是,如果pk
不限制为非空,那么它会产生不同的答案:
COUNT(possibly_null)
计算possibly_null
列中包含非空值的行数。
COUNT(DISTINCT pk)
也计算行数(因为主键不允许重复)。
COUNT(DISTINCT possibly_null_or_dup)
计算possibly_null_or_dup
列中不同非空值的数量。
COUNT(DISTINCT possibly_duplicated)
计算possibly_duplicated
列中NOT NULL
列中不同(必然非空)值的数量。
通常,我会写COUNT(*)
;它是SQL的原始推荐表示法。同样,使用EXISTS
子句,我通常会写WHERE EXISTS(SELECT * FROM ...)
,因为这是最初的推荐符号。替代品应该没有任何好处;优化器应该看到更加模糊的符号。
答案 2 :(得分:9)
这取决于您使用的数据库类型以及某些情况下的表类型。
例如,使用MySQL,count(*)
在MyISAM表下会很快,但在InnoDB下会很慢。在InnoDB下,您应该使用count(1)
或count(pk)
。
答案 3 :(得分:6)
Books on line说“COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
”
“1”是非空表达式,因此它与COUNT(*)
相同。
优化程序将其识别为 琐碎 ,因此提供相同的计划。 PK是唯一且非空(至少在SQL Server中),因此COUNT(PK)
= COUNT(*)
这与EXISTS (SELECT * ...
或EXISTS (SELECT 1 ...
请参阅ANSI 92 spec,第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.
答案 4 :(得分:5)
至少在Oracle上他们都是一样的:http://www.oracledba.co.uk/tips/count_speed.htm
答案 5 :(得分:-1)
我觉得性能特征从DBMS变为DBMS。一切都取决于他们如何选择实施它。由于我在oracle上广泛工作,我从这个角度讲述。
COUNT(*) - 将整行提取到结果集中以便传递给count函数,如果该行不为null,则count函数将聚合为1
COUNT(1) - 不会获取任何行,而是当where匹配时,为表中的每一行调用count为常量值1。
Count(PK) - oracle中的PK被编入索引。这意味着Oracle必须只读取索引。通常,索引B +树中的一行比实际行小许多倍。因此,考虑到磁盘IOPS速率,与整行相比,Oracle可以通过单个块传输从Index获取多倍的行。这会导致查询的吞吐量增加。
从这里你可以看到第一个计数是最慢的,最后一个计数是Oracle中最快的。