小编典典

COUNT(*)vs.COUNT(1)vs.COUNT(pk):哪个更好?

sql

我经常会发现以下三种变体:

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

据我所知,它们都做相同的事情,我发现自己在代码库中使用了这三个。但是,我不喜欢用不同的方式做同样的事情。我应该坚持哪一个?他们中的任何一个都比其他两个更好吗?


阅读 258

收藏
2021-05-05

共1个答案

小编典典

底线

使用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
)

用null计数

而且,如果字段的名称与表名称匹配,则使字段可为空也不是一个好习惯。假设您在fruit字段上具有值“香蕉”,“苹果”,NULL,“梨”
。这不会计算所有行,只会产生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
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
2021-05-05