一、select 1 from table;
与 select anycol(目的表集合中的任意一行)from table;
与 select * from table;
从作用上来说是没有差别的,都是查看是否有记录,一般是作条件查询用的。select 1 from table中的1是一常量(可以为任意数值),查到的所有行的值都是它,但从效率上来说,1>anycol>*,因为不用查字典表。
注意:
当只关心数据表有多少记录行而不需要知道具体的字段值时,类似“select 1 from table”是一个很不错的SQL语句写法,它通常用于子查询。
这样可以减少系统开销,提高运行效率。因为这样写的SQL语句,数据库引擎就不会去检索数据表里每条具体的记录和每条记录里每个具体的字段值并将它们放到内存里,而是根据查询到有多少记录行存在就输出多少个“1”,每个“1”代表有1行记录,同时选用数字1还因为它所占用的内存空间最小,当然用数字0的效果也一样。
测试:
-
select 1 from table
增加临时列,每行的列值是写在select后的数。这条sql语句中是1。 -
select count(1) from table
不管count(a) 的 a值如何变化,得出的值总是table表的行数。 -
select sum(1) from table
计算临时列的和。
在Oracle中用 1 测试了一下,发现结果如下:
- 测试结果,得出一个行数和table表行数一样的临时列,每行的列值是1;
- 得出一个数,该数是table表的行数;
- 得出一个数,该数是table表的行数;
然后又用“2”测试,结果如下:
- 得出一个行数和table表行数一样的临时列,每行的列值是2;
- 得出一个数,该数是table表的行数;
- 得出一个数,该数是table表的行数×2的数。
再用不同的数测试:
- 得出一个行数和table表行数一样的临时列,每行的列值是写在select后的数;
- 还是得出一个数,该数是table表的行数;
- 得出一个数,该数是table表的行数×写在select后的数。
综上所述:第一种的写法是增加临时列,每行的列值是写在select后的数;第二种是不管count(a)的a值如何变化,得出的值总是table表的行数;第三种是计算临时列的和。
二、count(列名) 、count(常量) 、count(*)
【强制】不要使用 count(列名) 或 count(常量) 来替代 count(*) , count(*) 是 SQL 92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*) 会统计值为 NULL 的行,而 count(列名) 不会统计此列为 NULL 值的行。
【强制】 count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct col 1, col 2 ) 如果其中一列全为 NULL ,那么即使另一列有不同的值,也返回为 0。
【强制】当某一列的值全是 NULL 时, count(col) 的返回结果为 0,但 sum(col) 的返回结果为NULL ,因此使用 sum() 时需注意 NPE 问题。
正例:可以使用如下方式来避免 sum 的 NPE(NullPointerException) 问题:
select if ( isNull ( sum(g) ) ,0, sum(g) ) from table;
1️⃣count(1) and count(*)
当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count(*)用时多!
从执行计划来看,count(1)和count(*)的效果是一样的。但是在表做过分析之后,count(1)会比count(*)的用时少些(1w以内数据量),不过差不了多少。
如果count(1)是聚集索引时,那肯定是count(1)快,但是差的很小。
因为count(*),自动会优化指定到那一个字段。所以没必要去count(1),用count(),sql会帮你完成优化的。因此:在有聚集索引时count(1)和count(*)基本没有差别!
2️⃣count(1) and count(字段)主要区别
- count(1) 会统计表中的所有的记录数,包含字段为null 的记录。
- count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段为null 的记录。
3️⃣count(*) 和 count(1)和count(列名)区别
执行效果上:
- count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
- count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
- count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。
执行效率上:
- 列名为主键,count(列名)会比count(1)快
- 列名不为主键,count(1)会比count(列名)快
- 如果表多个列并且没有主键,则 count(1)的执行效率优于 count(*)
- 如果有主键,则 select count(主键)的执行效率是最优的
如果表只有一个字段,则 select count(*) 最优。
4️⃣实例分析
create table tab
(name char(1),
age char(2));
insert into tab values
('a', '14'),
('a', '15'),
('a', '15'),
('b', NULL),
('b', '16'),
('c', '17'),
('d', null),
('e', '');
select
name,count(name),count(1),count(*),count(age),count(distinct(age))
from tab
group by name;
三、SQL查找是否“存在”
根据条件从数据库表中查询『有』与『没有』,只有两种状态。
1️⃣常见写法
业务代码中,需要根据一个或多个条件,查询是否存在记录,不关心有多少条记录。普遍的 SQL 写法如下:
select count(*) from table where a = 1 AND b = 2;
业务代码:
##### Java写法:
int num = countDao.countDataByCondition(params);
if ( num > 0 ) {
//当存在时,执行这里的代码
} else {
//当不存在时,执行这里的代码
}
2️⃣优化之后
select 1 from table where a = 1 AND b = 2 limit 1;
业务代码:
##### Java写法:
Integer exist = existDao.existDataByCondition(params);
if ( exist != NULL ) {
//当存在时,执行这里的代码
} else {
//当不存在时,执行这里的代码
}
sql 不再使用 count,而是改用 limit 1,让数据库查询时遇到一条就返回,不要再继续查找还有多少条。明知只有或者只要一条查询结果,使用 “limit 1”,可以避免全表扫描,找到对应结果就不会再继续扫描了。