MySQL实战45讲 第十四讲笔记

count(*)的实现方式

不同的存储引擎在实现count(*)的方式上不同

MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回
这个数,效率很高;
而 InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面
读出来,然后累积计数。
如果加入了where条件,MyISAM也不可能返回那么快。

show table status

使用命令,会返回TABLE_ROWS,但是这个数是基于采样计数的不够准确。

区别引擎和show table status

MyISAM 表虽然 count(*) 很快,但是不支持事务;
show table status 命令虽然返回很快,但是不准确;
InnoDB 表直接 count(*) 会遍历全表,虽然结果准确,但会导致性能问题。

如果用缓存系统存储计数

存在丢失更新和数据不同步的情况,因为缓存和数据库同时修改并非原子操作。
把计数放在 Redis 里面,不能够保证计数和 MySQL 表里的数据精确一致的原因,
是这两个不同的存储构成的系统,不支持分布式事务,无法拿到精确一致的视图。而把计数值也放在 MySQL 中,就解决了一致性视图的问题。

数据库保存计数

  • 不会丢失更新
  • 同时利用事务特性,同步计数和实际表内容

不同count用法

count语义,聚合函数,对于返回的结果集合一行行地进行判断,如果count的值不为空,计数加一,最后返回累计值。
count(*)、count(主键 id) 和 count(1) 都表示返回满足条件的结果集的总行数;而
count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。

  • count(*),优化器优化了 count(*) 的语义为“取行数”
  • count(主键 id),InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返
    回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
  • count(字段)
  1. 如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;
  2. 如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值取出来再判断一下,不是 null 才累加
  • count(1) InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一
    行,放一个数字“1”进去,判断是不可能为空的,按行累加。

结论

按照效率排序的话,count(字段) 以我建议你,尽量使用 count(*)。

你可能感兴趣的:(MySQL实战45讲 第十四讲笔记)