mysql表字段超过多少影响性能 mysql表多少效率会下降

一直有传言说,MySQL 表的数据只要超过 2000 万行,其性能就会下降。而本文作者用实验分析证明:至少在 2023 年,这已不再是 MySQL 表的有效软限制。

传言
互联网上有一则传言说,我们应该避免单个 MySQL 表中的数据超过 2000 万行,否则表的性能就会下降——当数据量超过这个软限制时,你就会发现 SQL 的查询速度会比平时慢很多。这是多年前针对 HDD 做出的判断。我想知道,时至 2023 年,SSD 上的 MySQL 是否仍然有此限制。如果真的有,那么原因是什么呢?

环境
数据库

▶ MySQL 版本: 8.0.25

▶ 实例类型:AWS db.r5.large(2vCPUs, 16GiB RAM)

▶ EBS 存储类型:General Purpose SSD(gp2)

测试客户端

▶ Linux 内核版本:6.1

▶ 实例类型:AWS t2.micro(1 vCPU, 1GiB RAM)

实验设计
创建具有相同结构、但大小不同的表。我一共创建了 9 个表,数据行数分别为:10 万、20 万、50 万、100 万、200 万、500 万、1000 万、2000 万、3000 万、5000 万和 6000 万。

  1. 创建几个具有相同结构的表:
CREATE TABLE row_test(
`id` int NOT NULL AUTO_INCREMENT,
`person_id` int NOT NULL,
`person_name` VARCHAR(200),
`insert_time` int,
`update_time` int,
PRIMARY KEY (`id`),
KEY `query_by_update_time` (`update_time`),
KEY `query_by_insert_time` (`insert_time`)
);
  1. 插入不同的数据。我使用了测试客户端和表复制的方式创建了这些表。脚本可参考:https://github.com/gongyisheng/playground/blob/main/mysql/row_test/insert_data.py。
# test client
INSERT INTO {table} (person_id, person_name, insert_time, update_time) VALUES ({person_id}, {person_name}, {insert_time}, {update_time})
# copy
create table like <table>
insert into (`person_id`, `person_name`, `insert_time`, `update_time`)
select `person_id`, `person_name`, `insert_time`, `update_time` from

person_id、person_name、insert_time 和 update_time 的值是随机的。

  1. 使用测试客户端执行以下 sql 查询来测试性能。脚本可参考:https://github.com/gongyisheng/playground/blob/main/mysql/row_test/select_test.py。
select count(*) from <table> -- full table scan
select count(*) from <table> where id = 12345 -- query by primary key
select count(*) from <table> where insert_time = 12345 -- query by index
select * from <table> where insert_time = 12345 -- query by index, but cause 2-times index tree lookup
  1. 查看 innodb 缓冲池状态。
SHOW ENGINE INNODB STATUS
SHOW STATUS LIKE 'innodb_buffer_pool_page%

结果
查询1:select count(*) from
在这里插入图片描述

这种查询会执行全表扫描,MySQL 并不擅长这种工作。

▶ 第一轮:没有缓存。第一次执行查询时,缓冲池中没有缓存数据。

▶ 第二轮:有缓存。当缓冲池中已经有数据缓存时执行查询,通常在第一次查询执行完之后。

观察结果:

1. 第一轮查询的执行时间超出了后面几次。

在这里插入图片描述
原因是 MySQL 使用了 innodb_buffer_pool 来缓存数据页。在第一次执行查询之前,缓冲池是空的,所以 MySQL 必须进行大量的磁盘 I/O 才能从 .idb 文件加载表。但在第一次执行结束后,缓冲池中存储了数据,后续查询可以直接读取内存,避免磁盘 I/O,因此速度更快。该过程称为 MySQL 缓冲池预热。

2. select count(*) from < table > 会设法将整个表加载到缓冲池。

在这里插入图片描述

我比较了实验前后 innodb_buffer_pool 的统计数据。运行查询后,如果缓冲池足够大,则其使用量变化等于表的大小。否则,只有部分表会缓存在缓冲池中。原因是查询 select count(*) from table 会做全表扫描,并做逐行统计。如果没有缓存,就需要将完整的表加载到内存中。为什么?因为 Innodb 支持事务,它不能保证事务在不同时间看到同一张表。全表扫描是获得准确行数的唯一安全方法。

3. 如果缓冲池不能容纳全表,则会爆发查询延迟。

在这里插入图片描述
我注意到 innodb_buffer_pool 的大小会极大地影响查询性能,因此我尝试在不同的配置下运行查询。当使用 11G 缓冲区,而表的大小达到 5000 万行时,就会爆发查询延迟。接着,我将缓冲区缩减到 7G,当表的大小达到 3000 万行时,爆发了查询延迟。最后,我将缓冲区缩减到 3G,当表的大小仅为 2000 万行时,就爆发了查询延迟。很明显,如果表中的数据无法缓存在缓冲池中,则 select count(*) from

必须执行昂贵的磁盘 I/O,这会导致查询运行时间直线上升。

4. 对于没有缓存的查询,查询花费的时间与表的大小呈线性关系,与缓冲池大小无关。

在这里插入图片描述
当没有缓存时,查询花费的时间由磁盘 I/O 决定,与缓冲池大小无关。在 IOPS 相同的情况下,是否使用 select count(*) 预热缓冲池并没有区别。

5. 如果无法完整地缓存整个表,则有无缓存的查询运行时间差异是恒定的。

另请注意,如果无法完整地缓存整个表,虽然查询运行时会突然上升,但运行时是可预测的。无论表的大小如何,有无缓存的时间差异是恒定的。原因是表的部分数据缓存在缓冲区中,这里的时间差异来自从缓冲区读取数据节省的时间。

查询2,3:select count(*) from where = 12345
在这里插入图片描述
这个查询使用了索引。由于不是范围查询,MySQL 只需要利用 B+ 树的路径从上到下查找页面,并将这些页面缓存到 innodb 缓冲池中即可。

我创建的表的 B+ 树的深度都是 3,因此前面的 3~4 次 I/O 都被拿来预热缓冲区,平均耗时 4~6 毫秒。之后,再次运行相同的查询,MySQL 就会直接从内存中查找结果,耗时为 0.5 毫秒,约等于网络 RTT。如果缓存页面长时间未命中,并从缓冲池中逐出,则必须再次从磁盘加载该页面,这样就需要磁盘 I/O(最多 4 次)。

查询4:select * from where = 12345
在这里插入图片描述
这个查询涉及两次索引查找。由于 select * 需要查询获取的 person_name、person_id 字段并不在索引中,因此在查询执行期间,数据库引擎必须查找 2 个 B+ 树。它首先查找 insert_time B+ 树,获取目标行的主键,然后查找主键 B+ 树,获取该行的完整数据,如下图所示:

在这里插入图片描述
这就是我们应该在生产中避免 select * 的原因。此次实验证实,此查询加载的页面块比查询 2 或 3 多出了 2 倍,且最高可达 8 倍。查询的平均运行时间为 6~10 毫秒,也是查询 2 或 3 的 1.5~2 倍。

传言是怎么来的
在这里插入图片描述
首先,我们需要知道 innodb 索引页的物理结构。默认页面大小为 16k,由页眉、系统记录、用户记录、页面导向器和尾部组成。只有剩下的 14~15k 用来存储数据。

假设你使用 INT 作为主键(4 字节),每行 1KB 的有效负载。每个叶页可以存储 15 行,一个指向该页的指针需要 4+8=12 字节。因此,每个非叶页最多可以容纳 15k / 12 字节 = 1280 个指针。如果你有一个 4 层的 B+ 树,它最多可以容纳 1280128015 = 24.6M 行数据。

回到 HDD 占据市场主导地位,且 SSD 对于数据库而言过于昂贵的时代,4 次随机 I/O 可能是我们可以容忍的最坏情况,而使用 2 次索引树查找的查询甚至会使情况变得更糟。当时的工程师想要控制索引树的深度,不希望它们太深。而如今 SSD 越来越流行,随机 I/O 比以前便宜了,因此我们应该反思一下 10 年前的规则。

顺便说一句,5 层 B+ 树可以容纳 128012801280*15 = 31.4B 行数据,超过了 INT 所能容纳的最大数据量。对每行大小的不同假设将导致不同的软限制,或小于或大于 2000 万行。例如,在我的实验中,每一行大约是 816 字节(我使用 utf8mb4 字符集,所以每个字符占用 4 个字节),4 层 B+ 树可以容纳的软限制是 29.5M。

结论
▶ Innodb 缓存池的大小、表的大小决定了是否会出现性能降级。

▶ 判断是否需要拆分 MySQL 表的一个更有意义的指标是查询运行时/缓冲池命中率。如果查询总是命中缓冲区,则不会有任何性能问题。2000 万行只是一个经验值。

▶ 除了拆分 MySQL 表之外,增加 Innodb 缓存池的大小和数据库的内存也是一个选择。

▶ 如果可能,请避免在生产中使用 select *,这类语句在最坏的情况下会导致 2 次索引树查找。

▶ (我个人的意见)考虑到 SSD 现在越来越流行,2000 万行不再是 MySQL 表的有效软限制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/670116.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入分析 Android Service (完)

文章目录 深入分析 Android Service (完)1. Service 的生命周期管理2. Service 的生命周期方法2.1 onCreate()2.2 onStartCommand(Intent intent, int flags, int startId)2.3 onBind(Intent intent)2.4 onUnbind(Intent intent)2.5 onRebind(Intent intent)2.6 onDestroy() 3.…

springboot 项目集成 knife4j

官方版本推荐 版本依赖 spring boot 2.3.12.RELEASE 和 knife4j 2.0.9 引入依赖 完整的pom.xml文件 <!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter --> <dependency><groupId>com.github.xiaoymin</groupI…

JavaScript笔记二-JavaScript基础语法

1、标识符 命名规则 第一个字符必须是一个字母、下划线&#xff08; _ &#xff09;或一个美元符号&#xff08; $ &#xff09;。其它字符可以是字母、下划线、美元符号或数字。按照惯例&#xff0c;ECMAScript 标识符采用驼峰命名法。标识符不能是关键字和保留字符。 2、字…

CDN——内容分发网络

目录 为什么使用CDN CDN是如何工作的 类型 推模式&#xff08;Push&#xff09; 拉模式&#xff08;Pull&#xff09; 缺点 例子 内容分发网络&#xff08;CDN&#xff09;是一组在地理上广泛分布的服务器&#xff0c;它们一起工作以提供互联网内容的快速交付。通常静态…

以sqlilabs靶场为例,讲解SQL注入攻击原理【15-17关】

【less-15&#xff1a;布尔盲注】 单引号闭合 1. or (length(database())) -- 数字&#xff1a;判断数据库长度&#xff1b; 2. or (ascii(substr(database(),1,1))) -- 数字&#xff1a;获取组成数据库的字符&#xff1b; 3. or (ascii(substr((select table_nam…

机器学习学习

机器学习类型(按学习方式分):监督学习、半监督学习、无监督学习、强化学习; 通过已知标签训练集训练模型,使用模型及逆行预测、测试; 向量表示法,其中每一维对应一个特征(feature)或者称为属性,记为[x1,x2,...,xn] 特征值、特征、标签,共同完成训练集的数据填充,最…

STM32作业实现(二)串口控制led

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

基于Chan-Vese算法的图像边缘提取matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................................................ % 迭代更新水平集函数 err[]…

GIS Java 生成四至图

目录 前言 操作步骤&#xff1a; 1&#xff0c;求出多边形的四至点 2&#xff0c;下载地图 3&#xff0c;绘制多边形 前言 对于地图上的一个多边形地块&#xff0c;其四至图就是能够覆盖这个多边形的最小矩形&#xff0c;也就是求出这个多边形的最东点&#xff0c;最西点&…

CATIA进阶操作——创成式曲面设计入门(1)线架设计,三维点、直线、平面、曲线

目录 引出三维空间点生成三维直线三维平面三维曲线总结异形弹簧新建几何体草图编辑&#xff0c;画一条样条线进行扫掠&#xff0c;圆心和半径画出曲面上的螺旋线再次选择扫掠&#xff0c;圆心和半径 其他自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自定义信号重…

搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL(四)

上一篇&#xff1a;搭建基于Django的博客系统增加广告轮播图&#xff08;三&#xff09; 下一篇&#xff1a;基于Django的博客系统之用HayStack连接elasticsearch增加搜索功能&#xff08;五&#xff09; Sqlite3数据库迁移到MySQL 数据库 迁移原因 Django 的内置数据库 SQL…

亚马逊对IP的要求是什么?

IP的全称为Internet Protocol&#xff0c;是TCP/IP体系中的网际层协议&#xff0c;IP只为主机提供一种无连接、不可靠的、尽力而为的数据包传输服务。IP规定网络上所有的设备都必须有一个独一无二的IP地址&#xff0c;就好比是邮件上都必须注明收件人地址&#xff0c;邮递员才能…

鸿蒙OS初识

学习官网&#xff1a;https://www.harmonyos.com/cn/develop 准备 注册&#xff0c;安装软件&#xff08;node:12, DevEco Studio&#xff09;&#xff1a; https://developer.harmonyos.com/cn/docs/documentation/doc-guides/software_install-0000001053582415#ZH-CN_TOP…

OpenAI 推出ChatGPT Edu,为高校定制版本

近日&#xff0c;OpenAI 宣布推出 ChatGPT Edu&#xff0c;这是一款专为高校打造的 ChatGPT 版本&#xff0c;旨在帮助学生、教师、研究人员和校园运营部门以负责任的方式部署和使用 AI。 ChatGPT Edu 由 GPT-4o 提供支持&#xff0c;具备强大的文本和图像推理能力&#xff0c;…

【笔记】Sturctured Streaming笔记总结(Python版)

目录 相关资料 一、概述 1.1 基本概念 1.2 两种处理模型 &#xff08;1&#xff09;微批处理 &#xff08;2&#xff09;持续处理 1.3 Structured Streaming和Spark SQL、Spark Streaming关系 二、编写Structured Streaming程序的基本步骤 三、输入源 3.1 File源 &am…

微服务架构-微服务实施

目录 一、概述 二、微服务拆分 2.1 概述 2.2 拆分原则 2.3 拆分方法 2.3.1 以数据为维度进行拆分 2.3.2 按照使用场景拆分 2.3.3 重要和非重要的拆分 2.3.4 变和不变的拆分 三、微服务通信 3.1 概述 3.2 微服务通信方式选择 3.3 微服务编排 3.4 API接口设计 3.5 …

实验报告 Java输入和输出

实验目的&#xff1a; 掌握Java 输入输出流的应用 掌握缓冲流的应用。 实验要求&#xff1a; &#xff08;1&#xff09;掌握字节输入输出流的操作 &#xff08;2&#xff09;掌握字符输入输出流的操作 &#xff08;3&#xff09;理解字节流和字符流的区别 &#xff08;…

游戏找不到steam_api64.dll如何解决,全面解析原因及解决方法

在现代游戏中&#xff0c;Steam平台已经成为了玩家们下载、安装和玩游戏的主要渠道之一。然而&#xff0c;有些玩家可能会遇到一个问题&#xff0c;即游戏找不到steam_api64.dll文件。这个问题可能会导致游戏无法正常运行或启动。本文将详细介绍如何解决这个问题&#xff0c;帮…

深度网络学习笔记(一)——self-attention机制介绍和计算步骤

self-attention机制介绍及其计算步骤 前言一、介绍和意义二、 计算细节2.1 计算Attention Score2.2 计算value2.3 计算关联结果b2.4 统一计算 三、总结 前言 Transformer是一种非常常见且强大的深度学习网络架构&#xff0c;尤其擅长处理输出为可变长度向量序列的任务&#xf…