MySQL 5.7下InnoDB对COUNT(*)的优化

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: MySQL 5.7下InnoDB对COUNT(*)的优化

0、导读

饱受诟病的InnoDB表COUNT(*)性能问题在5.7下做了优化,果真如此吗?

1、经典需求:InnoDB表COUNT(*)

InnoDB引擎表经常被抱怨执行COUNT(*)的效率太差,因此此类需求通常会被建议用其他方法来满足,比如另外加一个计数器表,或者用SHOW TABLE STATUS查看大概数量。

不过,从MySQL 5.7.2起,这个问题得到了解决,我们来看看。

2、MySQL 5.7版本InnoDB对COUNT(*)的优化

MySQL每发布一个新版本,都会放出相应的Release Notes,我们注意到5.7.2版本的发布说明中提到:

InnoDB: SELECT COUNT(*) FROM t statements now invoke a single handler call to the storage engine to scan the clustered index and return the row count to the Optimizer. Previously, a row count was typically performed by traversing a smaller secondary index and invoking a handler call for each record. A single handler call to the storage engine to count rows in the clustered index generally improves SELECT COUNT(*) FROM t performance. However, in the case of a large clustered index and a significantly smaller secondary index, performance degradation is possible compared to performance using the previous, non-optimized implementation. For more information, see Limits on InnoDB Tables.

简单地说就是:COUNT(*)会选择聚集索引,进行一次内部handler函数调用,即可快速获得该表总数。我们可以通过执行计划看到这个变化,例如:

image.png

很明显,在查询优化器阶段就已经得到优化了,相比效率应该杠杠的吧,我们稍后再来对比看看。

补充说下,5.7以前的版本中,COUNT(*)请求通常是:扫描普通索引来获得这个总数。也来看看5.6下的执行计划是怎样的:

image.png

可以看到,可以利用覆盖索引来完成COUNT(*)请求。

3、对比测试

先看一组测试数据:

count(*)对比测试

MySQL 5.6.33

MySQL 5.7.15

相差

表数据量

8976914

9000270

100.26%

耗时(秒)

5.459952

1.142340

20.92%

可以看到,两次数据量相当,但SQL耗时5.7约只有5.6的1/5,这个效率还是不错的吧。

我们来看看5.6和5.7版本下的status和profiling对比情况:

image.png

4、别高兴得太早

看完上面的对比测试,相信您已经心动了吧,但还别高兴得太早哦,官方文档里其实埋了一个伏笔:

InnoDB: SELECT COUNT(*) FROM t statements now invoke a single handler call to the storage engine to scan the clustered index and return the row count to the Optimizer. Previously, a row count was typically performed by traversing a smaller secondary index and invoking a handler call for each record. A single handler call to the storage engine to count rows in the clustered index generally improves SELECT COUNT(*) FROM t performance. However, in the case of a large clustered index and a significantly smaller secondary index, performance degradation is possible compared to performance using the previous, non-optimized implementation. For more information, see Limits on InnoDB Tables.

简言之,就是说如果聚集索引较大(或者说表数据量较大),没有完全加载到buffer pool中的话,有可能反而会更慢,还不如用原先的方式。

下面我们来测试下,读取tpcc测试表stock,该表有1亿行记录,表空间文件约65GB,而innodb buffer pool只分配了12G,这时候再看下对比数据:

count(*)对比测试

MySQL 5.6.33

MySQL 5.7.15

相差

表数据量

1亿

1亿

0.00%

耗时(秒)

693.66

5331.69

768.63%

在这种情况下,5.7版本反而慢的夸张,悲剧啊~

那么在5.7下的大表,有没有办法仍旧采用以前的方法来做COUNT(*)统计呢。当然可以了,我们可以强制指定普通索引,不过还需要加上WHERE条件,否则还是不行。后来搜了下,发现这是个bug,印风(zhaiwx)已经报告给官方了,bug id:81854。

image.png

这次的SQL执行耗时和在5.6下的就基本一样了。

4、后记

5.7版本整体挺赞的,不过还是有不少地方需要完善,期待能更成熟起来。

参考

1. MySQL 5.7.2 Release Notes:http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-2.html

2. Limits on InnoDB Tableshttp://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html



            </div>
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
10月前
|
关系型数据库 MySQL
mysql统计数据表中同一字段不同状态的COUNT()语句
mysql统计数据表中同一字段不同状态的COUNT()语句
67 0
|
6月前
|
SQL 关系型数据库 MySQL
解决MySQL count统计数目错误的问题
解决MySQL count统计数目错误的问题
51 0
|
7月前
|
SQL 算法 关系型数据库
【MySQL系列】统计函数(count,sum,avg)详解
文章目录 🌈一、COUNT函数 创建一个表T1 1.COUNT函数的定义: 2.COUNT函数的使用方式: 1️⃣count(*) (1)count(*)定义: (2)具体使用: (3)
|
7月前
|
NoSQL 关系型数据库 MySQL
MySQL学习笔记-不同count统计的比较
MySQL学习笔记-不同count统计的比较
42 0
|
9月前
|
SQL 存储 关系型数据库
为什么mysql的count()方法这么慢?
为什么mysql的count()方法这么慢?
71 0
|
9月前
|
关系型数据库 MySQL 数据挖掘
数据统计与计数:解析MySQL中的COUNT()函数
在数据库管理中,统计某一列数据的行数是常见的数据分析任务,COUNT()函数正是用于帮助我们实现这一目标的工具。
157 0
|
10月前
|
关系型数据库 MySQL 索引
【MySQL】count(1)、count(*)、count(字段)、count(主键)的区别
【MySQL】count(1)、count(*)、count(字段)、count(主键)的区别
166 0
|
11月前
|
SQL 存储 关系型数据库
MySQL中count(*)和information_schema.tables中的table_rows值不相同
MySQL中count(*)和information_schema.tables中的table_rows值不相同
275 0
|
11月前
|
存储 关系型数据库 MySQL
MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析
MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析
119 0
MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析
|
12月前
|
存储 SQL 安全
Mysql报错注入原理分析(count()、rand()、group by)
Mysql报错注入原理分析(count()、rand()、group by)
174 0