当前位置: 首页 > news >正文

计算 MySQL 表行的成本是多少?

当计算表中的所有行时,将使用什么索引?好吧,MySQL文档文档对此提供了一个直接的答案,引用:

InnoDB 通过遍历最小的可用二级索引来处理 SELECT COUNT(*) 语句除非索引或优化器提示指示优化器使用
不同的索引。如果不存在二级索引,则 InnoDB 通过扫描聚集索引来处理 SELECT COUNT(*) 语句。

通过一个简单的 sysbench 表示例,首先让我们检查一下查询计划:

mysql > explain select count(*) from sbtest1;
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | sbtest1 | NULL       | index | NULL          | k_1  | 4       | NULL | 986400 |   100.00 | Using index |
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

正如预期的那样,查询优化器选择了二级索引并打算对其执行扫描。运行查询将相应地增加处理程序,并在慢速日志中报告相同的情况:

mysql > flush status;
Query OK, 0 rows affected (0.00 mysql > select count(*) from sbtest1;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.17 sec)mysql > show status like 'Handler_read%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Handler_read_first    | 1       |
| Handler_read_key      | 1       |
| Handler_read_last     | 0       |
| Handler_read_next     | 1000000 |
| Handler_read_prev     | 0       |
| Handler_read_rnd      | 0       |
| Handler_read_rnd_next | 0       |
+-----------------------+---------+
7 rows in set (0.01 sec)

第一个惊喜是,在上述执行后,慢日志没有报告任何rows_examined

# Time: 2025-02-07T10:14:28.548037Z
# User@Host: msandbox[msandbox] @ localhost []  Id:     9
# Schema: db1  Last_errno: 0  Killed: 0
# Query_time: 0.173279  Lock_time: 0.000006  Rows_sent: 1  Rows_examined: 0  Rows_affected: 0  Bytes_sent: 62
use db1;
SET timestamp=1736696128;
select count(*) from sbtest1;

如果没有可用的辅助密钥怎么办?第二个示例表仅定义了主键:

mysql > desc sbtest2;
+-------+-----------+------+-----+---------+----------------+
| Field | Type      | Null | Key | Default | Extra          |
+-------+-----------+------+-----+---------+----------------+
| id    | int       | NO   | PRI | NULL    | auto_increment |
| k     | int       | NO   |     | 0       |                |
| c     | char(120) | NO   |     |         |                |
| pad   | char(60)  | NO   |     |         |                |
+-------+-----------+------+-----+---------+----------------+
4 rows in set (0.01 sec)mysql > explain select count(*) from sbtest2;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | sbtest2 | NULL       | index | NULL          | PRIMARY | 4       | NULL | 986400 |   100.00 | Using index |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

第二个惊喜来了:处理程序不会改变!

mysql > flush status;
Query OK, 0 rows affected (0.00 sec)mysql > select count(*) from sbtest2;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.04 sec)mysql > show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 0     |
| Handler_read_last     | 0     |
| Handler_read_next     | 0     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+
7 rows in set (0.00 sec)

在另一个表中,相同的查询成本是否会有所不同,这次没有定义任何索引

mysql > desc sbtest3;
+-------+-----------+------+-----+---------+-------+
| Field | Type      | Null | Key | Default | Extra |
+-------+-----------+------+-----+---------+-------+
| id    | int       | NO   |     | 0       |       |
| k     | int       | NO   |     | 0       |       |
| c     | char(120) | NO   |     |         |       |
| pad   | char(60)  | NO   |     |         |       |
+-------+-----------+------+-----+---------+-------+
4 rows in set (0.00 sec)mysql > explain select count(*) from sbtest3;
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
|  1 | SIMPLE      | sbtest3 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 985734 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
1 row in set, 1 warning (0.00 sec)mysql > select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.05 sec)mysql > show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 0     |
| Handler_read_last     | 0     |
| Handler_read_next     | 0     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+
7 rows in set (0.00 sec)

除了观察执行时间(与具有主键的表相当)之外,很难判断,因为状态处理程序既不会递增,也不会从慢速日志中Rows_examined信息。此外,全局 InnoDB 计数器(如 Innodb_rows_read)以及性能架构表统计信息在使用聚集索引(显式或隐式)进行计数时也不会更改!

mysql > select id from sbtest1 limit 1; select id from sbtest2 limit 1; select id from sbtest3 limit 1;
+--------+
| id     |
+--------+
| 731065 |
+--------+
1 row in set (0.00 sec)+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.01 sec)+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)mysql > select table_schema,table_name,rows_fetched from sys.schema_table_statistics where table_schema="db1";
+--------------+------------+--------------+
| table_schema | table_name | rows_fetched |
+--------------+------------+--------------+
| db1          | sbtest1    |            1 |
| db1          | sbtest2    |            1 |
| db1          | sbtest3    |            1 |
+--------------+------------+--------------+
3 rows in set (0.01 sec)mysql > select count(*) from sbtest1; select count(*) from sbtest2; select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.21 sec)+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.03 sec)+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.03 sec)mysql > select table_schema,table_name,rows_fetched from sys.schema_table_statistics where table_schema="db1";
+--------------+------------+--------------+
| table_schema | table_name | rows_fetched |
+--------------+------------+--------------+
| db1          | sbtest1    |      1000001 |
| db1          | sbtest2    |            1 |
| db1          | sbtest3    |            1 |
+--------------+------------+--------------+
3 rows in set (0.01 sec)

当不涉及辅助键时,在上面的运行中显然会被忽略!那么我们如何检查在 count 查询执行期间实际读取了什么索引,以及必须获取多少数据呢?我只能想到一种方法 – 在新重新启动的空闲服务器上,我们可以检查 Buffer Pool 内容(前提innodb_buffer_pool_load_at_startup = OFF

建议只在空闲时间进行检查!!!!!

mysql > select TABLE_NAME,INDEX_NAME,count(*) from INFORMATION_SCHEMA.INNODB_BUFFER_PAGE where TABLE_NAME like "`db1`.%" GROUP BY TABLE_NAME,INDEX_NAME;
Empty set (0.19 sec)mysql > select count(*) from sbtest1; select count(*) from sbtest2; select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.22 sec)+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.20 sec)+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.87 sec)mysql > select TABLE_NAME,INDEX_NAME,count(*) from INFORMATION_SCHEMA.INNODB_BUFFER_PAGE where TABLE_NAME like "`db1`.%" GROUP BY TABLE_NAME,INDEX_NAME;
+-----------------+-----------------+----------+
| TABLE_NAME      | INDEX_NAME      | count(*) |
+-----------------+-----------------+----------+
| `db1`.`sbtest1` | k_1             |      833 |
| `db1`.`sbtest2` | PRIMARY         |    13713 |
| `db1`.`sbtest3` | GEN_CLUST_INDEX |    14302 |
+-----------------+-----------------+----------+
3 rows in set (0.26 sec)

根据上述结果,我们可以看到加载了多少个索引页面来执行计数,其中小型二级索引胜出,因为它不包含数据。在这种情况下,它并没有直接转化为执行时间,具体原因等我明白了再给大家开篇贴来说

相关文章:

计算 MySQL 表行的成本是多少?

当计算表中的所有行时,将使用什么索引?好吧,MySQL文档文档对此提供了一个直接的答案,引用: InnoDB 通过遍历最小的可用二级索引来处理 SELECT COUNT(*) 语句除非索引或优化器提示指示优化器使用…...

Pygame介绍与游戏开发

提供pygame功能介绍的文档:Pygame Front Page — pygame v2.6.0 documentation 基础语法和实现逻辑 与CLI不同,pygame提供了图形化使用界面GUI(graphical user interface)基于图像的界面可以创建一个有图像和颜色的窗口 要让py…...

webpack配置方式

1. 基本配置文件 (webpack.config.js)(导出一个对象) 最常见的方式是通过 webpack.config.js 文件来配置 Webpack,导出一个对象。你可以在这个文件中导出一个配置对象,指定入口、输出、加载器、插件等。 // webpack.config.js m…...

10. k8s二进制集群之Kube Scheduler部署

在开始之前需要准备什么?创建kube-scheduler证书请求文件【即证书的生成⓵】根据上面证书配置文件生成kube-scheduler证书【即证书的生成⓶】创建与关联kube-scheduler配置文件(为后面生成系统服务做准备)创建kube-scheduler服务配置文件【准备系统服务⓵】创建kube-schedul…...

java实现8583报文解析技术详解

文章目录 概要整体架构流程技术名词解释技术细节小结概要 ISO 8583协议是金融交易系统中广泛使用的通信协议,用于规范报文的格式和数据交换。解析8583报文是实现金融交易系统的关键技术之一。本文将详细介绍8583报文解析的核心实现,重点关注解析算法和关键代码逻辑。 8583报…...

k8s服务发现有哪些方式?

在 Kubernetes 中,服务发现是指如何让应用程序在集群内互相找到并通信。Kubernetes 提供了多种服务发现的方式,适应不同的使用场景。以下是 Kubernetes 中常见的服务发现方式: 1. 环境变量(Environment Variables) 概…...

【SqlServer】SQL Server Management Studio (SSMS) 下载、安装、配置使用及卸载——保姆级教程

超详细的 SQL Server Management Studio (SSMS) 下载、安装、连接数据库配置及卸载教程 SQL Server Management Studio (SSMS) 是微软提供的图形化管理工具,主要用于连接、管理和开发 SQL Server 数据库。以下是详细的 SSMS 下载、安装、连接数据库以及卸载的完整教…...

[ESP32:Vscode+PlatformIO]添加第三方库 开源库 与Arduino导入第三方库的区别

前言 PlatformIO与Arduino在添加第三方库方面的原理存在显著差异 在PlatformIO中,第三方库的使用是基于项目(工程)的。具体而言,只有当你为一个特定的项目添加了某个第三方库后,该项目才能使用该库。这些第三方库的文…...

音频文件格式——AAC、OGG和FLAC

3.AAC文件格式 3.1 封装格式解析 高级音频编码 (Advanced Audio Coding) 是一种用于有损数字音频压缩的音频编码标准。它被设计为 MP3 格式的继承者,在相同比特率下通常可以获得比 MP3 更高的音质。AAC有两种封装格式: ADIF&am…...

BUU26 [极客大挑战 2019]HardSQL1

输入一些SQL关键词,发现空格,,union,and,by都被过滤了 被过滤,就用like替代 发现登录成功,可以注入 报错注入 注意 1.这里过滤了空格,就用()将内容包裹起来 比如说&#xff1a…...

多光谱成像技术在华为Mate70系列的应用

华为Mate70系列搭载了光谱技术的产物——红枫原色摄像头,这是一款150万像素的多光谱摄像头。 相较于普通摄像头,它具有以下优势: 色彩还原度高:色彩还原准确度提升约 120%,能捕捉更多光谱信息,使拍摄照片色…...

借助 Cursor 快速实现小程序前端开发

借助 Cursor 快速实现小程序前端开发 在当今快节奏的互联网时代,小程序因其便捷性、高效性以及无需下载安装的特点,成为众多企业和开发者关注的焦点。然而,小程序的开发往往需要耗费大量的时间和精力,尤其是在前端开发阶段。幸运…...

【deepseek】ollama chatbox webui 本地部署deepseek 踩坑记录

部署 1、前往Ollama官网下载跨平台工具 官网直达:https://ollama.com/download 2、挑选适合自己设备的模型版本,获取运行指令 访问模型库:https://ollama.com/library/deepseek-r1 ▌配置建议: • 入门级:1.5B版本&…...

在离线的服务器上部署Python的安装库

在离线服务器上部署 Python 安装库(如 SQLAlchemy、pandas、pyodbc 等),可以使用以下方法: 方法 1:在联网机器上下载依赖,拷贝到离线服务器 适用于:服务器完全无法访问互联网。 步骤 1. 在联网…...

计算机网络笔记再战——理解几个经典的协议2

理解互联网与TCP/IP 下面,我们将会开始理解互联网这个东西,进一步的,我们会理解何为TCP/IP 我们的互联网就是一个巨大的网状结构,需要注意的是——每一个网状的节点之间都是使用一个叫做NOC,Network Operation Center…...

设计高效的测试用例:从需求到验证

在现代软件开发过程中,测试用例的设计一直是质量保证(QA)环节的核心。有效的测试用例不仅能够帮助发现潜在缺陷,提升软件质量,还能降低后期修复成本,提高开发效率。尽管如此,如何从需求出发&…...

git reset 命令

git reset 的作用 git reset 是一个非常强大的命令,用于将当前分支的 HEAD(即当前指向的提交)重置到指定的提交。它还可以根据参数的不同,对工作区(Working Directory)和暂存区(Staging Area&a…...

docker被“遗忘”的那些参数该如何拯救

一、docker容器启动时没有指定端口,如何在不删除容器的情况下配置端口呢 在 Docker 中,如果容器启动时没有指定端口映射,可以通过以下步骤在不删除容器的情况下配置端口: 方法 1: 使用 docker commit 和 docker run 提交容器为新…...

BFS算法——广度优先搜索,探索未知的旅程(下)

文章目录 前言一. N叉树的层序遍历1.1 题目链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/description/1.2 题目分析:1.3 思路讲解:1.4 代码实现: 二. 二叉树的锯齿形层序遍历2.1 题目链接:htt…...

Python分享20个Excel自动化脚本

在数据处理和分析的过程中,Excel文件是我们日常工作中常见的格式。通过Python,我们可以实现对Excel文件的各种自动化操作,提高工作效率。 本文将分享20个实用的Excel自动化脚本,以帮助新手小白更轻松地掌握这些技能。 1. Excel单…...

PHP和Node.js哪个更爽?

先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

HTML 列表、表格、表单

1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...