《丁奇-MySQL45讲-14/15》之归纳总结

14 | count(*) 这么慢,我该怎么办?

  • InnoDB下count的实现方式是一行一行地读取数据然后累积计数,这也是为什么记录越来越多会导致查询越来越慢。之所以这么设计是因为一行数据可能存在多个版本,InnoDB也无法确定,只能一行一行地获取并判断。

  • InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。所以,普通索引树比主键索引树小很多。对于 count(*) 这样的操作,遍历哪个索引树得到的结果逻辑上都是一样的。因此,MySQL 优化器会找到最小的那棵树来遍历。

  • 哪些计数方式可以代替MySQL的计数

  1. 使用缓存系统保存,读和更新都很快,但可能因为缓存系统异常重启导致丢失更新,也可能会出现缓存系统读到的计数和数据库实际存储的记录数不一致的情况。

  2. 在数据库保存计数,单独放到一张表中,利用MVCC特性可以规避不一致的情况,而MySQL本身就支持崩溃恢复数据。

  3. 不同的count用法,按照效率排序的话,count(*) 约等于 cont(1) > count(主键id) 约等于 count(字段),后两者的比较个人理解是有可能相等的。

  • count()、count(主键id)、count(1)都表示返回满足条件的结果集的总行数,count(字段)则表示返回满足条件的数据行立案,参数"字段"部位null的总个数,说明count()一定是大于等于count(字段)。

  • 对于count(主键id)来说,InnoDB引擎会遍历整张表,把每一行的id取出来,返回给Server层,Server判断不可能为空的,进行累加;对于count(1)来说,InnoDB引擎会遍历整张表,但不取值,Server层对于返回的每一行(空行??),放一个数字"1"进去,判断是不可能为空的,进行累加;这两者的区别在于前者需要解析数据行获取到id,以及拷贝字段值的操作。

  • 对于count(字段)来说,InnoDB遍历整张表,一行一行地取出对应的字段返回给Server层(丁奇老师认为这里还要在判断,但我记得通常判断都是交由Server去判断的,所以我认为不需要判断),判断不能为null,不是null才会进行累加。

  • count(*)是个例外,并不会取出所有字段的值,而是专门做了优化,不取值,难道返回Server的也是空行吗?,最后进行累加。

  • 思考题:应该先插入操作记录还是先更新计数?

因为更新计数是因为加X锁的,而该锁只有等事务提交后才会提交,所以如果先更新计数的话可能会导致长事务,之前也有提到过针对加锁的操作尽量放在最后面以便减少不同事务之间锁的竞争。

15 | 答疑文件(一):日志和索引相关问题

  • 一个事务的binlog是有完整的格式:
  1. statement格式的binlog,最后会有commit。

  2. row格式的binlog,最后会有一个XID event,也就是事务ID

  • binlog row格式:主要记录哪一行记录被修改了,修改成什么样子,简单来说就是直接记录了数据的变化,如果一条SQL语句造成多条记录被修改,那么每一条都会被记录下来,特别是对于表结构的修改,那表中的每条记录都会发生变化,产生大量的日志;不过在主从复制过程不会出现复制问题,毕竟都只是数据的复制。在实践过程可以发现日志是不可读的,这些数据都被加密过了。

  • binlog statement格式:主要记录修改数据的SQL,同时也会记录执行SQL时的上下文信息,保证在从节点上执行SQL的结果和主节点是一致的,在主从复制过程中可能会出现复制问题或者数据不一致问题;不过它的日志量较少从而节省了存储资源。在实践过程中可以发现该格式下的日志可以直接看到SQL。

  • redo log和binlog是怎么关联的:redo log和binlog都有一个共同的字段XID,也就是事务ID,崩溃恢复时会顺序扫描redo log,如果碰到既有prepare,又有commit的redo log就直接提交,如果只有prepare而没有commit的redo log,那么就拿着XID去binlog找对应的事务,如果没找到的话就会回滚,如果找到了那就提交事务。

  • 为什么binlog不能做崩溃恢复:数据存储通常是以数据页为单位的,所以恢复也是需要以数据页为单位的,redo log记录的就是数据页的更新,而binlog记录的是数据变化或者是SQL,所以在崩溃恢复的时候是没办法使用binlog进行数据恢复。另外一方面是binlog没有checkpoint,所以不知道要从哪里开始恢复。

posted @ 2021-03-24 19:59  zliawk  阅读(94)  评论(0)    收藏  举报