14 | count(*)这么慢,我该怎么办?
该思维导图由 AI 生成,仅供参考
count(*) 的实现方式
- 深入了解
- 翻译
- 解释
- 总结
MySQL中的count(*)语句在不同引擎中有不同的实现方式。MyISAM引擎直接返回存储在磁盘上的总行数,效率高;而InnoDB引擎需要逐行读取数据并累积计数,导致执行速度变慢。针对频繁统计表行数的需求,建议自行计数或使用缓存系统保存计数,如Redis服务,但存在数据不一致和丢失更新的问题。另外,文章还详细解释了count()函数的不同用法的性能差别,以及在不同情况下使用事务来确保计数准确的方法。总的来说,文章深入浅出地介绍了MySQL技术特点,为读者提供了有益的技术参考。
《MySQL 实战 45 讲》,新⼈⾸单¥68
全部留言(250)
- 最新
- 精选
- 发条橙子 。置顶老师 ,我这边有几个问题 : 1. 看到老师回复评论说 count(id) 也是走普通索引 ,那是不是也算是优化了 , 我以为 count(字段) 是走的聚集索引 。老师的意思是 count(字段) 是走二级索引,但是不一定是数据最少的索引树的意思是么 2. count(*) 的话, innodb 还会有取数判空这样的判断逻辑么 ,还是直接取行数 +1 了 , 还是按所取索引类型分情况。 允许为 null 的索引是不是行数比较少, 取的总数会不会有问题呢 3. 我这边试了一下 , 库里总共 30w 数据 。 第一次用 count(*) 是 120多ms , 第二次就是 60多 ms 。 第三次用了 count(1) ,也是60多ms 。 请问 count(*) 这两次的前后时间差是什么原因,也会走缓存 ? 4. 另一个问题是一个题外话 ,我看老师的例子事务级别应该都是 rr 。 我偶然看到我们公司事务隔离级别是 rc 。 我比较惊讶,就去问 DBA 为什么是 rc 而不是默认的 rr 。 她说一般都是用的 rc ,我想问现在公司一般都是 rc 么, 请问老师现在用的隔离级别是什么 ?? 在我的印象里 ,rr 保证事务的隔离性会更好一些吧 。 我google 了一下, rc 会不会在某些场景下出现一些问题,但是没有查出来相关结果。老师能不能讲解一下,rc 的话会在哪些场景下会踩坑么 。 (我之前码代码都是按照 rr 级别下的思维码的代码)
作者回复: 1. 如果有索引用到这个字段的话,比较大可能会用到这个索引,比主键索引小 2. 索引字段就算是NULL,上面的id也不是的 3. 进了Buffer pool 的原因吧 4. 嗯,rc用得挺多的,但是原因可能只是因为“以前是这么用的”。 使用rc可能有问题,也可能没问题。但是我觉得DBA不知道为什么这么选,这个是问题。 rc本身的问题其实前面我们说过一些,比如不是一致性读。后面也会有文章说到。
2018-12-151523 - 倪大人置顶看到有同学说会话A是幻读,其实图一的会话B才是幻读吧?
作者回复: 这些都不叫幻读,幻读的意思是“用一个事务里面,后一个请求看到的比之前相同请求看到的,多了记录出来”。 改了不算 大家关注一下这个问题。 好问题
2018-12-151671 - 果然如此置顶一、请问计数用这个MySQL+redis方案如何: 1.开启事务(程序中的事务) 2.MySQL插入数据 3.原子更新redis计数 4.如果redis更新成功提交事务,如果redis更新失败回滚事务。 二、.net和java程序代码的事务和MySQL事务是什么关系,有什么相关性?
作者回复: 1. 好问题,不会还是没解决我们说的一致性问题。如果在3、4之间插入了 Session B的逻辑呢 2. 我估计就是启动事务(执行begin),结束时提交(执行commit)吧,没有了解过所有框架,不确定哈
2018-12-141527 - 包包up置顶从并发系统性能的角度考虑,应该先插入操作记录,再更新计数表。 知识点在《行锁功过:怎么减少行锁对性能的影响?》 因为更新计数表涉及到行锁的竞争,先插入再更新能最大程度地减少了事务之间的锁等待,提升了并发度。
作者回复: 好几个同学说对,你第一个标明出处👍🏿
2018-12-1418682 - 李二木一直以为带*查询效率是最差的,平时查询特意加了 count(ID) 查询。罪过啊。
作者回复: 😄 来得及来得及
2018-12-1516113 - 菜鸡一只count(id)和count(这段)都是要把每一行的该字段值取出来,然后判断是否为空,那为什么count(id)的效率要高?
作者回复: count(id)可能会选择最小的索引来遍历 而count(字段)的话,如果字段上没有索引,就只能选主键索引
2019-02-011190 - 某、人老师我先问个本章之外的问题: 1.rr模式下,一张表上没有主键和唯一键,有二级索引c.如果是一张大表,删除一条数据delete t where c=1. 在主库上利用二级索引,在根据虚拟的主键列回表删除还挺快.但是在备库上回放特别慢,而且状态是system lock,是因为binlog event里没有包含虚拟主键列.导致在备库回放的时候,必须全表扫描,耗时特别久?还是其他原因 2.回放过程中,在备库delete一条语句是被阻塞的,insert又是可以的,说明只在记录上的X锁没有gap锁。 但是如果在主库session A begin,delete where c=1.在开启一个session B,在主库上操作也是delete阻塞,insert正常.不过等session A执行完成,不提交.insert都阻塞了,说明最后上了gap锁。有点没明白这儿的上锁逻辑是什么? 3.还有就是备库回放binlog,相对于主库的一条update语句流程来说,从库回放哪些流程是省略了的啊, server层的应该都省略了,应该主要是引擎层的回放,这里有点模糊从库是怎么回放的binlog event? 因为第一个问题从库回放的时候,从库上的二级索引貌似没起作用,直接就在聚簇索引上做的更新。 感谢老师
作者回复: 1. 对,这个是个bug, 从库上会全表扫描。MariaDB 的版本有解决这个问题。生产上我们最好不允许没有主键的表 2. 按照你问的,gap锁没问题了。delete 被锁是因为行锁吧。从库重放就是因为走全表扫描按行锁下来触发的 3. 出现这个问题肯定是binlog设置了row格式。 这样binlog里面有所有值。如果你有主键的话,就是主键查,没有的话…就是全表了
2018-12-14926 - 小动物很困我记得有一个并发插入的方法,就是说计数表对同一个表开很多行,然后计数增加对这些数据随机做加法,当做count操作的时候取sum,这样对行锁竞争会削弱.
作者回复: 是的,咱们专栏07篇也有类似的介绍😆
2019-01-22321 - 不忘初心对于 count(主键 id) ,server层拿到ID,判断ID是不可能为空的按行累加。这个地方,是不是又点问题,既然是主键ID,是一定不会为空的,这个server层还需要判断不为空吗
作者回复: 嗯,代码就是这么写的 我也觉得可以优化一下… 不过现在就这样😓
2018-12-2616 - 陈天境碰到大部分情形都是带条件查询的count,,这个怎么解?
作者回复: 索引条件过滤完后还多少行?如果行数少(几百行?)就没关系直接执行了
2018-12-1469