数据库SQL面试题:数据库SQL的count(*)、count(1)和count(字段)的区别和性能差异

在统计行数时,常用的是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)代替。

参考