百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

新特新解读 MySQL 8.0 对 count()的优化

toyiye 2024-06-21 12:13 8 浏览 0 评论

原创: 杨涛涛

摘要:MySQL 8.0 取消了 sql_calc_found_rows 的语法,以后求表 count(*) 的写法演进为直接 select。

我们知道,MySQL 一直依赖对 count(*) 的执行很头疼。很早的时候,MyISAM 引擎自带计数器,可以秒回;不过 InnoDB 就需要实时计算,所以很头疼。以前有多方法可以变相解决此类问题,比如:

1. 模拟 MyISAM 的计数器

比如表 ytt1,要获得总数,我们建立两个触发器分别对 insert/delete 来做记录到表 ytt1_count,这样只需要查询表 ytt1_count 就能拿到总数。ytt1_count 这张表足够小,可以长期固化到内存里。不过缺点就是有多余的触发器针对 ytt1 的每行操作,写性能降低。这里需要权衡。

2. 用 MySQL 自带的 sql_calc_found_rows 特性来隐式计算

依然是表 ytt1,不过每次查询的时候用 sql_calc_found_rows 和 found_rows() 来获取总数,比如:

mysql> select sql_calc_found_rows * from ytt1 where 1 order by id desc limit 1;
+------+------+
 | id | r1 |
+------+------+
 | 3072 | 73 |
+------+------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message | 
+---------+------+-------------------------------------------------------------------------------------------------------------------------+
| Warning | 1287 | SQL_CALC_FOUND_ROWS is deprecated and will be removed in a future release. Consider using two separate queries instead. |
 +---------+------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select found_rows() as 'count(*)';
+----------+
 | count(*) |
+----------+
| 3072 |
+----------+
1 row in set, 1 warning (0.00 sec)

这样的好处是写法简单,用的是 MySQL 自己的语法。缺点也有,大概有两点:

1. sql_calc_found_rows 是全表扫。

2. found_rows() 函数是语句级别的存储,有很大的不确定性,所以在 MySQL 主从架构里,语句级别的行级格式下,从机数据可能会不准确。不过行记录格式改为 ROW 就 OK。所以最大的缺点还是第一点。

从 warnings 信息看,这种是 MySQL 8.0 之后要淘汰的语法。

3. 从数据字典里面拿出来粗略的值

 mysql> select table_rows from information_schema.tables where table_name = 'ytt1';
 +------------+
 | TABLE_ROWS |
 +------------+
 | 3072 |
 +------------+
 1 row in set (0.12 sec)

那这样的适合新闻展示,比如行数非常多,每页显示几行,一般后面的很多大家也都不怎么去看。缺点是数据不是精确值。

4. 根据表结构特性特殊的取值

这里假设表 ytt1 的主键是连续的,并且没有间隙,那么可以直接

mysql> select max(id) as cnt from ytt1;
+------+
| cnt |
+------+
| 3072 |
+------+
1 row in set (0.00 sec)

不过这种对表的数据要求比较高。

5. 标准推荐取法(MySQL 8.0.17 建议)

MySQL 8.0 建议用常规的写法来实现。

 mysql> select * from ytt1 where 1 limit 1;
 +----+------+
 | id | r1 |
 +----+------+
 | 87 | 1 |
 +----+------+
 1 row in set (0.00 sec)
 mysql> select count(*) from ytt1;
 +----------+
 | count(*) |
 +----------+
 | 3072 |
 +----------+
 1 row in set (0.01 sec)

第五种写法是 MySQL 8.0.17 推荐的,也就是说以后大部分场景直接实时计算就 OK 了。

MySQL 8.0.17 以及在未来的版本都取消了sql_calc_found_rows 特性,可以查看第二种方法里的 warnings 信息。相比 MySQL 5.7,8.0 对 count(*) 做了优化,没有必要在用第二种写法了。我们来看看 8.0 比 5.7 在此类查询是否真的有优化?

MySQL 5.7

 mysql> select version();
 +------------+
 | version() |
 +------------+
 | 5.7.27-log |
 +------------+
 1 row in set (0.00 sec)
 mysql> explain format=json select count(*) from ytt1\G
 *************************** 1. row ***************************
 EXPLAIN: {
 "query_block": {
 "select_id": 1,
 "cost_info": {
 "query_cost": "622.40"
 },
 "table": {
 "table_name": "ytt1",
 "access_type": "index",
 "key": "PRIMARY",
 "used_key_parts": [
 "id"
 ],
 "key_length": "4",
 "rows_examined_per_scan": 3072,
 "rows_produced_per_join": 3072,
 "filtered": "100.00",
 "using_index": true,
 "cost_info": {
 "read_cost": "8.00",
 "eval_cost": "614.40",
 "prefix_cost": "622.40",
 "data_read_per_join": "48K"
 }
 }
 }
 }
 1 row in set, 1 warning (0.00 sec)

MySQL 8.0 下执行同样的查询

 mysql> select version();
 +-----------+
 | version() |
 +-----------+
 | 8.0.17 |
 +-----------+
 1 row in set (0.00 sec)
 mysql> explain format=json select count(*) from ytt1\G
 *************************** 1. row ***************************
 EXPLAIN: {
 "query_block": {
 "select_id": 1,
 "cost_info": {
 "query_cost": "309.95"
 },
 "table": {
 "table_name": "ytt1",
 "access_type": "index",
 "key": "PRIMARY",
 "used_key_parts": [
 "id"
 ],
 "key_length": "4",
 "rows_examined_per_scan": 3072,
 "rows_produced_per_join": 3072,
 "filtered": "100.00",
 "using_index": true,
 "cost_info": {
 "read_cost": "2.75",
 "eval_cost": "307.20",
 "prefix_cost": "309.95",
 "data_read_per_join": "48K"
 }
 }
 }
 }
 1 row in set, 1 warning (0.00 sec)

从以上结果看出,第二个 SQL 性能(cost_info)相对第一个提升了一倍。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码