在统计行数时,常用的是count(*)。而在早期的数据库,这个*默认会被解析,在成少许的浪费,所以都建议写成count(1),而针对count(字段)这个写法并不常见。本文以GBase 8a数据库为例,介绍他们之间的区别。
目录导航
样例数据
样例数据共3行,2列。其中id列是数字,全部由值。name里是字符串,有数据没有填写,为NULL。
gbase> select * from tt1;
+------+-------+
| id | name |
+------+-------+
| 1 | First |
| 2 | |
| 3 | NULL |
+------+-------+
3 rows in set (Elapsed: 00:00:00.00)
coun(*) 和 count(1)
获得所有的行数。当然用count(2222)也行,这里只是count,统计行数。
gbase> select count(*) from tt1;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (Elapsed: 00:00:00.02)
gbase> select count(1) from tt1;
+----------+
| count(1) |
+----------+
| 3 |
+----------+
1 row in set (Elapsed: 00:00:00.01)
gbase> select count(222222) from tt1;
+---------------+
| count(222222) |
+---------------+
| 3 |
+---------------+
1 row in set (Elapsed: 00:00:00.01)
从结果看,没有任何区别。而且在现今主流的数据库,对*都做了优化,不再做解析之类的操作了,从性能角度讲,也和count(1)没有任何区别,可以大胆的用。
count(字段)
针对不同的字段,查询结果有不同。
gbase> select count(id) from tt1;
+-----------+
| count(id) |
+-----------+
| 3 |
+-----------+
1 row in set (Elapsed: 00:00:00.00)
gbase> select count(name) from tt1;
+-------------+
| count(name) |
+-------------+
| 2 |
+-------------+
1 row in set (Elapsed: 00:00:00.00)
可以看到count(id)结果是3,而count(name)结果为2。区别是name里有1行是NULL值。
性能差异
根据第三方的测试结果如下:除了PG,其它数据库都无任何影响。PG建议用count(*)更快一些。
MySQL: Doesn’t matter. Sometimes COUNT(1) was faster, sometimes COUNT(*) was faster, so all differences were only benchmark artifacts
Oracle: Doesn’t matter. Like MySQL
PostgreSQL: Does matter (!). COUNT(*) was consistently faster by around 10% on 1M rows, that’s much more than I had expected
SQL Server: Doesn’t matter. Like MySQL
总结
如果数据没有NULL值,那么三个用法的结果是完全一样的,但相对的count(字段)是要检查是否为NULL值,性能会略有损失。
如果数据里有NULL值,则count(字段)只返回非NULL的数据行数,与其它2个结果集是不同的。
所以,如果不是特意统计非NULL值,不建议用count(字段),而是用count(*)或count(1)代替。