时间:2021-05-24
count(*)
实现
1、MyISAM:将表的总行数存放在磁盘上,针对无过滤条件的查询可以直接返回
如果有过滤条件的count(*),MyISAM也不能很快返回
2、InnoDB:从存储引擎一行行地读出数据,然后累加计数
由于MVCC,在同一时刻,InnoDB应该返回多少行是不确定
样例
假设表t有10000条记录
session A session B session C BEGIN; SELECT COUNT(*) FROM t;(返回10000) INSERT INTO t;(插入一行) BEGIN; INSERT INTO t(插入一行); SELECT COUNT(*) FROM t;(返回10000) SELECT COUNT(*) FROM t;(返回10002) SELECT COUNT(*) FROM T;(返回10001)
最后时刻三个会话同时查询t的总行数,拿到的结果却是不同的
InnoDB默认事务隔离级别是RR,通过MVCC实现
优化
1、InnoDB是索引组织表
2、二级索引树占用的空间比聚簇索引树小很多
3、优化器会在保证逻辑正确的前提下,遍历最小的索引树,尽量减少扫描的数据量
show table status
SHOW TABLE STATUS同样通过采样来估算(非常不精确),误差能到40%~50%
维护计数
缓存
方案
缺点
丢失更新
1、Redis可能会丢失更新
2、解决方案:Redis异常重启后,到数据库执行一次count(*)
逻辑不精确 – 致命
1、场景:显示操作记录的总数和最近操作的100条记录
2、Redis和MySQL是两个不同的存储系统,不支持分布式事务,因此无法拿到精确的一致性视图
时序A
session B在T3时刻,查到的100行结果里面有最新插入的记录,但Redis还没有+1,逻辑不一致
时刻 session A session B T1 T2 插入一行数据R; T3 读取Redis计数;
查询最近100条记录; T4 Redis计数+1;
时序B
session B在T3时刻,查到的100行结果里面没有最新插入的记录,但Redis已经+1,逻辑不一致
时刻 session A session B T1 T2 Redis计数+1; T3 读取Redis计数;
查询最近100条记录; T4 插入一行数据R;
数据库
时刻 session A session B T1 T2 BEGIN;
表C中的计数值+1; T3 BEGIN;
读表C计数值;
查询最新100条记录;
COMMIT; T4 插入一行数据R;
COMMIT;
count的性能
语义
1、count()是一个聚合函数,对于返回的结果集,一行一行地进行判断
如果count函数的参数值不是NULL,累计值+1,否则不加,最后返回累计值
2、count(字段F)
3、count(主键ID)、count(1)、count(*)
4、Server层要什么字段,InnoDB引擎就返回什么字段
性能对比
count(字段F)
1、如果字段F定义为不允许为NULL,一行行地从记录里读出这个字段,判断通过后按行累加
2、如果字段F定义为允许NULL,一行行地从记录里读出这个字段,判断通过后按行累加
3、如果字段F上没有二级索引,只能遍历整张表(聚簇索引)
4、由于InnoDB必须返回字段F,因此优化器能做出的优化决策将减少
count(主键ID)
count(1)
count(*)
效率排序
样例
count(字段F)
无索引
user_ids上无索引,而InnoDB又必须返回user_ids字段,只能遍历聚簇索引
mysql> EXPLAIN SELECT COUNT(user_ids) FROM prop_action_batch_reward;+----+-------------+--------------------------+------+---------------+------+---------+------+----------+-------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+--------------------------+------+---------------+------+---------+------+----------+-------+| 1 | SIMPLE | prop_action_batch_reward | ALL | NULL | NULL | NULL | NULL | 16435876 | NULL |+----+-------------+--------------------------+------+---------------+------+---------+------+----------+-------+mysql> SELECT COUNT(user_ids) FROM prop_action_batch_reward;+-----------------+| count(user_ids) |+-----------------+| 17689788 |+-----------------+1 row in set (10.93 sec)有索引
1、serial_id上有索引,可以遍历uniq_serial_id_source_index
2、但由于InnoDB必须返回serial_id字段,因此不会遍历逻辑结果等价的更优选择idx_create_time
count(主键ID)
优化器选择了最优的索引idx_create_time来遍历,而非聚簇索引
mysql> EXPLAIN SELECT COUNT(id) FROM prop_action_batch_reward;+----+-------------+--------------------------+-------+---------------+-----------------+---------+------+----------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+--------------------------+-------+---------------+-----------------+---------+------+----------+-------------+| 1 | SIMPLE | prop_action_batch_reward | index | NULL | idx_create_time | 5 | NULL | 16436797 | Using index |+----+-------------+--------------------------+-------+---------------+-----------------+---------+------+----------+-------------+mysql> SELECT COUNT(id) FROM prop_action_batch_reward;+-----------+| count(id) |+-----------+| 17705383 |+-----------+1 row in set (4.54 sec)count(1)
count(*)
参考资料
《MySQL实战45讲》
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文详述了SQL优化中针对count、表的连接顺序、条件顺序、in及exist的优化,非常具有实用价值!详述如下:一、关于count看过一些网上关于count(
JavaWebServlet中Filter过滤器的详解1.简述Filter过滤器,对web服务器所有web资源进行过滤,从而实现一些特殊的功能(权限访问控制、过
商业网站中存在大量无效URL不利于搜索引擎收录。很多商业网站中都有产品条件过滤系统,大量过滤条件页面内容重复或极为类似,使得网站整体质量下降,同时大量过滤条件页
SUM是对符合条件的记录的数值列求和COUNT是对查询中符合条件的结果(或记录)的个数例如:表fruitidnameprice1apple3.002pear4.
MySQL数据类型中DECIMAL的用法实例详解在MySQL数据类型中,例如INT,FLOAT,DOUBLE,CHAR,DECIMAL等,它们都有各自的作用,下