在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
count(*) 实现 1、MyISAM:将表的总行数存放在磁盘上,针对无过滤条件的查询可以直接返回 如果有过滤条件的count(*),MyISAM也不能很快返回 2、InnoDB:从存储引擎一行行地读出数据,然后累加计数 由于MVCC,在同一时刻,InnoDB应该返回多少行是不确定 样例 假设表t有10000条记录
最后时刻三个会话同时查询t的总行数,拿到的结果却是不同的 InnoDB默认事务隔离级别是RR,通过MVCC实现
优化 1、InnoDB是索引组织表
2、二级索引树占用的空间比聚簇索引树小很多 3、优化器会在保证逻辑正确的前提下,遍历最小的索引树,尽量减少扫描的数据量
show table status mysql> SHOW TABLE STATUS\G; *************************** 1. row *************************** Name: t Engine: InnoDB Version: 10 Row_format: Dynamic Rows: 100256 Avg_row_length: 47 Data_length: 4734976 Max_data_length: 0 Index_length: 5275648 Data_free: 0 Auto_increment: NULL Create_time: 2019-02-01 17:49:07 Update_time: NULL Check_time: NULL Collation: utf8_general_ci Checksum: NULL Create_options: Comment: SHOW TABLE STATUS同样通过采样来估算(非常不精确),误差能到40%~50% 维护计数 缓存 方案
缺点 丢失更新 1、Redis可能会丢失更新 2、解决方案:Redis异常重启后,到数据库执行一次count(*)
逻辑不精确 – 致命 1、场景:显示操作记录的总数和最近操作的100条记录 2、Redis和MySQL是两个不同的存储系统,不支持分布式事务,因此无法拿到精确的一致性视图 时序A session B在T3时刻,查到的100行结果里面有最新插入的记录,但Redis还没有+1,逻辑不一致
时序B session B在T3时刻,查到的100行结果里面没有最新插入的记录,但Redis已经+1,逻辑不一致
数据库
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(*)
效率排序
样例 mysql> SHOW CREATE TABLE prop_action_batch_reward\G; *************************** 1. row *************************** Table: prop_action_batch_reward Create Table: CREATE TABLE `prop_action_batch_reward` ( `id` bigint(20) NOT NULL, `source` int(11) DEFAULT NULL, `serial_id` bigint(20) NOT NULL, `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `user_ids` mediumtext, `serial_index` tinyint(4) DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `uniq_serial_id_source_index` (`serial_id`,`source`,`serial_index`), KEY `idx_create_time` (`create_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 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
mysql> EXPLAIN SELECT COUNT(serial_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 | uniq_serial_id_source_index | 15 | NULL | 16434890 | Using index | +----+-------------+--------------------------+-------+---------------+-----------------------------+---------+------+----------+-------------+ mysql> SELECT COUNT(serial_id) FROM prop_action_batch_reward; +------------------+ | count(serial_id) | +------------------+ | 17705069 | +------------------+ 1 row in set (5.04 sec) 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) mysql> EXPLAIN SELECT COUNT(1) 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 | 16437220 | Using index | +----+-------------+--------------------------+-------+---------------+-----------------+---------+------+----------+-------------+ mysql> SELECT COUNT(1) FROM prop_action_batch_reward; +----------+ | count(1) | +----------+ | 17705808 | +----------+ 1 row in set (4.12 sec) count(*) mysql> EXPLAIN SELECT COUNT(*) 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 | 16437518 | Using index | +----+-------------+--------------------------+-------+---------------+-----------------+---------+------+----------+-------------+ mysql> SELECT COUNT(*) FROM prop_action_batch_reward; +----------+ | count(*) | +----------+ | 17706074 | +----------+ 1 row in set (4.06 sec) 参考资料 《MySQL实战45讲》 总结 以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对极客世界的支持。 |
请发表评论