MySQL Execution Plan--COUNT相关测试
COUNT全表记录
在MySQL中,相同的SQL不同的存储引擎执行计划不同:
对于MyISAM引擎,由于使用表锁进行并发控制,同一时间点多个并发线程执行相同查询获得的结果相同,且MyISAM存储引擎专门存储表总记录数,因此使用COUNT(*)查询全表记录时能直接返回。 而对于InnoDB存储引擎,由于使用MVCC和行锁进行并发控制,同一时间点多个并发线程执行相同查询获得的结果存在差异(每个回话的READVIEW不同),且没有专门存储表总记录数,因此每次查询都需要扫描全表或扫描某个索引的全部记录。 For transactional storage engines such as InnoDB, storing an exact row count is problematic. Multiple transactions may be occurring at the same time, each of which may affect the count. InnoDB does not keep an internal count of rows in a table because concurrent transactions might “see” different numbers of rows at the same time. Consequently, SELECT COUNT(*) statements only count rows visible to the current transaction. Prior to MySQL 5.7.18, InnoDB processes SELECT COUNT(*) statements by scanning the clustered index. As of MySQL 5.7.18, InnoDB processes SELECT COUNT(*) statements by traversing the smallest available secondary index unless an index or optimizer hint directs the optimizer to use a different index. If a secondary index is not present, the clustered index is scanned. Processing SELECT COUNT(*) statements takes some time if index records are not entirely in the buffer pool. For a faster count, create a counter table and let your application update it according to the inserts and deletes it does. However, this method may not scale well in situations where thousands of concurrent transactions are initiating updates to the same counter table. If an approximate row count is sufficient, use SHOW TABLE STATUS. InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference. For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL。
现有测试表TB101:
CREATE TABLE `tb101` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`C1` int(11) NOT NULL,
`C2` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM AUTO_INCREMENT=140001 DEFAULT CHARSET=utf8
对于没有WHERE条件的COUNT(*)/COUNT(1)/COUNT(ID)/COUNT(C1)的执行计划为:
mysql> EXPLAIN SELECT COUNT(*) FROM TB101 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: Select tables optimized away
1 row in set, 1 warning (0.00 sec)
对于没有WHERE条件的COUNT(C2)的执行计划为:
mysql> EXPLAIN SELECT COUNT(C2) FROM TB101 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB101
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 140000
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
可以发现,对于MyISAM存储引擎,在没有WHERE条件下,如果C1列为NOT NULL,则可以将COUNT(C1)与COUNT(*)和COUNT(1)做相同的处理。
针对上面的测试,对于InnoDB存储引擎,在没有WHERE条件下:
1、ID列为NOT NULL主键,COUNT(ID)和COUNT(1)或COUNT(*)的执行计划相同,返回结果相同。 2、C1列为NOT NULL,COUNT(C1)和COUNT(1)或COUNT(*)的执行结果相同,但执行计划不同。
COUNT(expr)异同
1、COUNT(1)和COUNT(*)等价,两者在执行计划和执行效率上完全相同。
个人推荐使用COUNT(1)替换COUNT(*),原因是简单直观,
他人推荐使用COUNT(1),原因是符合SQL92标准,阿里巴巴Java开发手册推荐。
2、COUNT(*)和COUNT(C1)不一定等价,两者执行计划和执行结果会存在差异。
COUNT(*):执行返回满足WHERE条件的行数,不考虑NULL值问题
COUNT(C1): 执行返回满足WHERE条件且C1不等于NULL的行数,不统计C1等于NULL的行。 换种理解思路:
对于MyISAM引擎表和InnoDB引擎表,无论是显式主键还是因此ROWID,都要求非空唯一,每行记录都肯定存在一个不为NULL的列(列组),因此计算COUNT(*)时不需要考虑NULL值问题。
一个有趣的扩展,如果C1为NOT NULL,那么COUNT(C1)与COUNT(1)的返回结果相同,那么MySQL会对此进行优化么?
现有测试表结果如下:
CREATE TABLE `tb01` (
`ID` int() NOT NULL AUTO_INCREMENT,
`C1` int() NOT NULL,
`C2` int() NOT NULL,
PRIMARY KEY (`ID`),
KEY `IDX_C2` (`C2`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8
查看COUNT(*)和COUNT(C1)的执行计划:
mysql> EXPLAIN SELECT COUNT(*) FROM TB01 WHERE C2<100 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB01
partitions: NULL
type: range
possible_keys: IDX_C2
key: IDX_C2
key_len: 4
ref: NULL
rows: 99
filtered: 100.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec) mysql> EXPLAIN SELECT COUNT(C1) FROM TB01 WHERE C2<100 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB01
partitions: NULL
type: range
possible_keys: IDX_C2
key: IDX_C2
key_len: 4
ref: NULL
rows: 99
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
从上面执行计划可以发现,在处理COUNT(*)时,仅需要使用IDX_C2即可完成查询,因此Extra为Using index,而在处理COUNT(C1)时,需要使用IDX_C2进行过滤后再执行回表查询,因此Extra为Using index condition。
针对上面的测试,MyISAM存储引擎和InnoDB存储引擎的测试结果相同。
COUNT(DISTINC ...)操作
MySQL官网解释为:
COUNT(DISTINCT expr,[expr...]) Returns a count of the number of rows with different non-NULL expr values. In MySQL, you can obtain the number of distinct expression combinations that do not contain NULL by giving a list of expressions. In standard SQL, you would have to do a concatenation of all expressions inside COUNT(DISTINCT ...).
在MySQL中允许执行:
SELECT COUNT(DISTINCT ID,C1) FROM TB02;
但不允许执行:
SELECT COUNT(ID,C1) FROM TB02;
总结
1、对于InnoDB和MyISAM存储引擎,COUNT(1)和COUNT(*)在任何场景下都等价,执行性能和执行计划相同。 2、在查询全表记录(没有WHERE条件)时,对于MyISAM存储引擎,存储引擎存储表总记录数,无需扫描数据因此查询可以很快返回,对于InnoDB存储引擎,需要扫描全表或某个索引的全部记录因此查询可能比较耗时。 3、对于MyISAM存储引擎,在没有WHERE条件情况下,如果列C1为NOT NULL,那么COUNT(C1)和COUNT(*)执行操作相同。 4、对于InnoDB存储引擎,如果列C1为主键,那么COUNT(C1)和COUNT(*)执行计划和执行效率相同,如果C1为NOT NULL,那么COUNT(C1)和COUNT(*)执行计划和执行效率不一定相同,只有在查询使用C1列上索引时才可能相同。
参考链接:
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count
https://dev.mysql.com/doc/refman/5.7/en/create-index.html
https://mp.weixin.qq.com/s/IOHvtel2KLNi-Ol4UBivbQ
MySQL Execution Plan--COUNT相关测试的更多相关文章
- Oracle SQL explain/execution Plan
From http://blog.csdn.net/wujiandao/article/details/6621073 1. Four ways to get execution plan(anyti ...
- sql server 执行计划(execution plan)介绍
大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...
- MySQL优化之COUNT(*)效率
MySQL优化之COUNT(*)效率 刚给一个朋友解决他写的Discuz!插件的问题,说到MySQL的COUNT(*)的效率,发现越说越说不清楚,干脆写下来,分享给大家. COUNT(*)与COUNT ...
- 用count(*)还是count(列名) || Mysql中的count()与sum()区别
Mysql中的count()与sum()区别 首先创建个表说明问题 CREATE TABLE `result` ( `name` varchar(20) default NULL, `su ...
- mysql中的count(primary_key)、count(1)、count(*)的区别
表结构如下: mysql> show create table user\G; *************************** 1. row ********************** ...
- mysql提示Column count doesn't match value count at row 1错误
mysql提示Column count doesn't match value count at row 1错误,后来发现是由于写的SQL语句里列的数目和后面的值的数目不一致, 比如insert in ...
- mysql错误:Column count doesn't match value count at row 1
mysql错误:Column count doesn't match value count at row 1 mysql错误:Column count doesn't match value cou ...
- Execution Plan 执行计划介绍
后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载. 下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...
- 【mysql】mysql统计查询count的效率优化问题
mysql统计查询count的效率优化问题 涉及到一个问题 就是 mysql的二级索引的问题,聚簇索引和非聚簇索引 引申地址:https://www.cnblogs.com/sxdcgaq8080/p ...
随机推荐
- 元素无法定位问题 NoSuchElementException: Message: no such element: Unable to locate element 解决方法
定位网页上某个按钮时,总是报错元素定位不到,具体如下:NoSuchElementException: Message: no such element: Unable to locate elemen ...
- 201871010111-刘佳华《面向对象程序设计(java)》第八周学习总结
201871010111-刘佳华<面向对象程序设计(java)>第八周学习总结 实验七 接口的定义与使用 实验时间 2019-10-18 第一部分:知识总结 接口的概念: ①java为了克 ...
- 201871010132-张潇潇-《面向对象程序设计(java)》第八周总结
201871010132-张潇潇<面向对象程序设计(java)>第八周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这 ...
- Python学习笔记4 高级特性_20170618
# 切片(获取list / tuple / 字符串 中指定的元素) l = list(range(10)) l[0:3] l[:3] # 0可以省略 l[:] # 全部 l[3:] # 最后的可以省略 ...
- 如何对jmeter设置IP欺骗
由于服务器出于安全考虑会对同一IP地址做过滤,所以如果想要达到正常的压测效果,我们需要在发请求时伪造出不同的IP地址.主要步骤分为以下3步:第一步:在负载机上绑定IP地址. 第二步:在要欺骗的http ...
- vue better-scroll
better-scroll在vue项目中的使用 2017年12月21日 18:01:09 阅读数:411 1.准备工作 在项目中安装better-scroll: npm install --save ...
- 快速获取 IP 地址
IP 地址可以分为两类,公用和私有(专用).公用 IP 是唯一的 IP 地址,可以从 Internet 访问.专用 IP 地址保留供您专用网络内部使用,而不会直接暴露给 Internet. 本文将介绍 ...
- appium--使用PyYAML封装Capability
前戏 YAML 语言的设计目标,就是方便人类读写.它实质上是一种通用的数据串行化格式. 它的基本语法规则如下. YAML大小写敏感: 使用缩进代表层级关系: 缩进只能使用空格,不能使用TAB,不要求空 ...
- hdu6492 暴力预处理 + 枚举
http://acm.hdu.edu.cn/showproblem.php?pid=6492 题意 他们一共有 n+m+2k 个人,包括 n+k 个男生,m+k 个女生,其中 k 对男女生为异性情侣, ...
- 多台Linux 7.x服务器具有相同的UUID网络链接参数,肿么办?
1.查看多台服务器的UUID网络链接参数是否相同 我这里使用SecureCRT的全部交互功能,直接批量输出 /etc/sysconfig/network-scripts/ifcfg-ens33 的内 ...