July's Blog

花有重开日,人无再少年

0%

七天带你玩转MySQL之SQL语句

查询

1
2
3
4
5
6
select ... from ....
where ...
group by ...
having ...
order by ...
limit ...;

执行顺序:

1
2
3
4
5
6
7
1 from
2 where
3 group by
4 select
5 having
6 order by
7 limit

group by

MySql从5.7版本开始默认开启only_full_group_by规则,规则核心原则如下,没有遵循原则的sql会被认为是不合法的sql

  1. order by后面的列必须是在select后面存在的
  2. selecthavingorder by后面存在的非聚合列必须全部在group by中存在

count(*)、count(1)、count(主键)、count(字段)的区别

以下,基于 InnoDB

含义区别

count()是一个聚合函数,对于返回的结果集,会逐行判断,若返回的不是 NULL,就会加 1,否则不加。
因此,count(*)、count(主键 id)和count(1)都表示返回满足条件的结果集的总行数;而count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。

性能区别

分析性能,考虑以下几个原则:

  1. server 层要什么就会返回什么;
  2. InnoDB 只返回必要的值;
  3. 优化器只优化了count(*)
  • 对于count(主键id),InnoDB 会遍历全表,取每行的主键 id,返回给 server 层,server 层拿到数据后,进行判断累加。
  • 对于count(1),InnoDB 仍遍历全表,但是不取值,server 层对返回的每一行数据新增一个 1,然后进行判断累加;
    因此,count(1)要更快些,因为无需取值。从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作。
  • 对于count(字段):
  1. 如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;
  2. 如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是 null 才累加。
  • 但是count(*)是例外,并不会把全部字段取出来,而是专门做了优化,不取值。count(*)肯定不是null,按行累加。

结论

按照效率排序的话

1
count(字段) < count(主键 id) < count(1) ≈ count(*)

所以我建议你,尽量使用count(*)

请作者喝冰阔落