2000万的行数在2023年仍然是 MySQL 表的有效软限制吗?

news2025/1/7 6:30:52

谣言

互联网上有传言说我们应该避免在单个 MySQL 表中有超过 2000 万行。否则,表的性能会下降,当它超过软限制时,你会发现 SQL 查询比平时慢得多。这些判断是在多年前使用HDD硬盘存储时做出的。我想知道在2023年对于基于SSD的MySQL数据库来说,这是否仍然成立,如果成立,原因是什么?

环境

· 数据库
MySQL 版本:8.0.25
实例类型:AWS db.r5.large (2vCPUs, 16GiB RAM)
EBS 存储类型:通用 SSD (gp2)
· 测试客户端
Linux 内核版本:6.1
实例类型:AWS t2.micro (1 vCPU,1GiB 内存)

实验设计

创建具有相同模式但大小不同的表。我创建了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`)
);

2. 插入不同行的表格。我使用测试客户端和复制来创建这些表。脚本可以在这里找到。

# 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 <new-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 的值是随机的。

3.使用测试客户端执行以下sql查询来测试性能。脚本可以在这里找到。

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

4.查看innodb缓冲池状态

SHOW ENGINE INNODB STATUS
SHOW STATUS LIKE 'innodb_buffer_pool_page%'

5.每次在表上测试完一定要重启数据库!刷新 innodb 缓冲池以避免读取旧缓存并得到错误结果!

结果

查询 1:select count(*) from <table>

这种查询会造成全表扫描,这是MySQL不擅长的。

No-cache round:(第一轮)当缓冲池中没有缓存数据时,第一次执行查询。
Cache round:(Other round)当缓冲池中已经有数据缓存时执行查询,通常在第一次执行之后。

几个观察:

1.第一次执行的查询运行时间比后面的要长

原因是MySQL使用了innodb_buffer_pool来缓存数据页。在第一次执行之前,缓冲池是空的,它必须进行大量的磁盘 I/O 才能从 .idb 文件加载表。但第一次执行后,数据存储在缓冲池中,后续执行可以通过内存计算得到结果,避免磁盘I/O,速度更快。该过程称为MySQL 缓冲池预热。

2.select count(*) from <table>将尝试将整个表加载到缓冲池

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

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

我注意到 innodb_buffer_pool 大小会对查询性能产生很大影响,因此我尝试在不同的配置下运行查询。当使用 11G 的缓冲池时,查询延迟的突增发生在表大小达到 50M 时。然后将缓冲池大小减小为 7G,查询延迟的突增发生在表大小为 30M 时。最后将缓冲池大小减小到 3G,查询运行时间的突增发生在表大小为 20M 时。很明显,如果表中的数据无法被缓存到缓冲池中,执行select count(*) from <table>就需要进行昂贵的磁盘 I/O 操作来加载数据,从而导致查询运行时间的突增。

4. 在不缓存的情况下,查询运行时间与表大小呈线性关系,与缓冲池大小无关。

无缓存循环运行时间由磁盘 I/O 决定,与缓冲池大小无关。select count(*)使用相同 IOPS 的存储磁盘预热缓冲池没有区别。

5. 如果表无法完全缓存在缓冲池中,那么无缓存轮和有缓存轮之间的查询运行时间差是恒定的。

同时注意到,尽管如果表无法完全缓存在缓冲池中会导致查询运行时间的突增,但运行时间是可预测的。无缓存轮运行时间和有缓存轮运行时间之间的差值是恒定的,无论表的大小如何。原因是表的部分数据被缓存在缓冲池中,这个差值表示了从缓冲池而不是磁盘进行查询所节省的时间。

查询 2、3:select count(*) from <table> where <index_column> = 12345

此查询使用索引。由于不是范围查询,只需要在B+树的路径中从上到下查找页面,并将这些页面缓存到innodb缓冲池中即可。

我创建的表的 B+ 树的深度都是 3,导致 3-4 次 I/O 来预热缓冲区,平均耗时 4-6ms。之后,如果我再次运行相同的查询,它会直接从内存中查找结果,即 0.5ms,等于网络 RTT。如果缓存页面长时间未命中并从缓冲池中逐出,则必须再次从磁盘加载该页面,这最多需要 4 次磁盘 I/O。

查询 4:select * from <table> where <index_column> = 12345

此查询导致 2 次索引查找。由于select *需要查询获取不包含在索引中的person_nameperson_id,因此在查询执行期间数据库引擎必须查找 2 个 B+ 树。它首先查找insert_timeB+ 树以获取目标行的主键,然后查找主键 B+ 树以获取该行的完整数据,如下图所示:

这就是我们在生产中应该避免的原因select *。并且在实验中,数据证实此查询加载的页面块比查询 2 或 3 多 2 倍,最多为 8。平均查询运行时间为 6-10 毫秒,也是查询 2 或 3 的 1.5 到 2 倍。

谣言是怎么来的

首先我们需要知道innodb索引页的物理结构。默认页面大小为 16k,由页眉、系统记录、用户记录、页面导向器和尾部组成。将只剩下 15-14k 来存储免费数据。

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

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

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

结论

  1. Innodb_buffer_pool 大小/表大小决定是否会出现性能下降。

  2. 一个更有意义的指标来判断是否需要拆分MySQL表是查询运行时间与缓冲池命中率的比值如果查询总是命中缓冲池,就不会有性能问题。2000万行只是基于经验的一个值。

  3. 除了拆表,增加InnoDB缓冲池大小或数据库内存也是一个选择。

  4. 在生产环境中,如果可能的话,尽量避免使用select *,因为在最坏的情况下会导致索引树的两次查找。

  5. (个人观点)考虑到SSD现在的普及,2000万行并不是MySQL表的一个非常有效的软限制。


来源:Yisheng's blog​

更多技术干货请关注公号“云原生数据库

squids.cn,基于公有云基础资源,提供云上 RDS,云备份,云迁移,SQL 窗口门户企业功能,

帮助企业快速构建云上数据库融合生态。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据学习篇10】Spark项目实战~网站转化率统计

学习目标/Target 掌握网站转化率统计实现思路 了解如何生成用户浏览网页数据 掌握如何创建Spark连接并读取数据集 掌握利用Spark SQL统计每个页面访问次数 掌握利用Spark SQL获取每个用户浏览网页的顺序 掌握利用Spark SQL合并同一用户浏览的网页 掌握利用Spark SQL统计每…

安卓基础巩固(三)多线程、数据存储、文件IO、SQLite

文章目录 多线程Handler相关概念UI线程/主线程MessageMessage QueueLooperHandler 使用步骤Handler.sendMessage&#xff08;&#xff09;Handler.post&#xff08;&#xff09; Handler 机制工作原理Handler内存泄露前置知识案例分析解决方案一&#xff1a;静态内部类弱引用解…

数据结构学习记录——图应用实例-六度空间(题目描述、算法思路、伪代码及解读、图解)

目录 题目描述 算法思路 伪代码 总体算法 BFS算法 伪代码解读 BFS算法 图解 题目描述 六度空间理论的核心观点是&#xff0c;人类社交网络中的任何两个人之间&#xff0c;平均只需要通过不超过六个中间人&#xff08;也就是六个社交关系&#xff09;就可以建立联系。换…

多台plc之间如何快速实现以太网无线连接?

常规来说&#xff0c;多台plc要实现以太网无线连接&#xff0c;首先要先确定以太网线必须正确连接&#xff0c;并建立物理连接。然后需要在PLC端设置好IP地址&#xff0c;以使不同PLC以相同协议可以实现通信交流。最后是建立PLC端数据采集及交换系统&#xff0c;要求在PLC端设置…

《封号码罗》关于js逆向猿人学第二题cookies里面m值的获取[纯扣算法](二十六)

这一题有点儿误打误撞的感觉。 本题使用了抓包工具Fiddler&#xff0c;m值在cookie里面&#xff0c;而且这个cookie是本地生成的 抓包发现有两次请求&#xff0c;第一次返回了一堆JS&#xff0c;而且cookie里面没有m值&#xff0c;第二次请求就带上了m值&#xff0c;所以m应该…

信号完整性分析基础知识之传输线和反射(七):带负载传输线、感性不连续引起的反射

带负载传输线 如果在传输线上有一个小的容性负载&#xff0c;信号会出现失真&#xff0c;上升时间也会降低。每个分立电容都会降低信号在其附近看到的阻抗。如果传输线上分布有多个容性负载&#xff08;例如一个总线上每隔1.2inch有一个2pF的连接器残桩&#xff0c;或者一个内…

单模光纤一维模场分布的MATLAB仿真

根据已知的单模光纤电场z分量分布&#xff0c;可以用MATLAB展示一维的模场分布 具体来说&#xff0c;通过数值计算解出给定光纤&#xff08;n_1&#xff0c;n_2&#xff0c;a&#xff09;参数时对应的V参量 通过特征方程解出V对应的W和U 通过这三个参数带入到光场的表达式中…

07. 算法之一致性哈希算法介绍

前言 哈希算法在程序开发中的很多地方都能看到他的身影&#xff0c;但是哈希有他的局限性&#xff0c;比如如果两个key哈希到同一个位置的时候&#xff0c;此时就不好处理。本节我们介绍一下常规处理方式。 1. 什么是哈希算法 哈希算法将任意长度的二进制值映射为较短的固定…

界面控件DevExtreme使用指南 - 如何自定义上下文菜单和工具栏

DevExtreme File Manager&#xff08;文件管理器&#xff09;小部件现在支持自定义内置的工具栏和上下文菜单&#xff0c;用户可以使用标准和定义的命令项填充项目集合&#xff0c;并配置设置来更改其外观和操作。 DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#x…

基于Keras-YOLO实现目标检测

Keras-YOLO 3项目使用Python语言实现了YOLO v3网络模型&#xff0c;并且可以导入Darknet网络预先训练好的权重文件信息直接使用网络进行目标识别。 1. 下载Keras-YOLO 3项目 执行如下命令下载Keras-YOLO 3项目代码&#xff1a; git clone https://github.com/qqwweee/keras-…

直播和短视频美颜sdk的开发流程、代码分析

目前&#xff0c;美颜技术是提高视频质量的重要手段之一&#xff0c;特别是短视频和直播两个行业。本文将介绍其开发流程和代码分析。 一、美颜SDK的开发流程 1.需求分析 首先我们需要明确的一点就是“需求”&#xff0c;例如&#xff1a;美颜效果、美颜程度、性能要求等。同…

解决找不到微信支付V3版本公钥问题

参考微信文档链接为签名验证-接口规则 | 微信支付商户平台文档中心 写的内容特别不明显&#xff0c;往下面看会找到 下载openssl工具使用命令从私钥证书中导出即可。

地图在线编辑平台,无基础轻松实现私域地图

位构云平台让用户轻松构建诸如空间信息管理、建筑信息管理及三维空间数据可视化、导航等类型应用的多平台、综合型地图引擎&#xff0c;基于OpenGLES/WebGL三维可视化技术体系的自主研发图形引擎&#xff0c;可以让开发者轻松构建运行在 Web、Android、iOS 等多平台的应用程序。…

安捷伦DSO80404B(Agilent)dso80404b租售回收 数字示波器

DSO80404B 是 Agilent 的 4 GHz、4 通道数字示波器。测量电子电路或组件中随时间变化的电压或电流信号&#xff0c;以显示振幅、频率和上升时间等。应用包括故障排除、生产测试和设计。 附加功能&#xff1a; 4 GHz 带宽&#xff0c;可升级至 13 GHz 4个模拟通道 高达 40 G…

day10 前端技术-HTMLCSS

HTML 含义:超文本标记语言,静态网页,用于在浏览器显示数据 双标签:<> </>,开始标签和结束标签同时出现 单标签: 属性名:属性后面的值都加双引号 常用的HTML标签 :文档的根标签 :HTML页面的头部标签 “”:页面标题 “”:页面主体部分 “ “ “ 到 ”:标题…

『树莓派云台机器人』02. 电脑连接树莓派 配置开发环境

目录 1. 下载ssh交互工具 Xshell 与XFTP&#xff08;有过相关使用经历的朋友可以跳过这一节内容&#xff09;2. 下载VNC远程控制工具软件3. 连接过程4. Xshell 命令工具5. XFTP 文件传送工具6. 关于联网总结 欢迎关注 『树莓派云台机器人』 博客&#xff0c;持续更新中 欢迎关注…

PoseiSwap IDO在Bounce上启动在即,如何参与?

目前&#xff0c;Nautilus Chain 生态基本完成测试&#xff0c;并即将在不久上线主网。PoseiSwap 作为 Nautilus Chain 上的首个 DEX&#xff0c;也即将面向市场并上线正式版本。我们看到&#xff0c; PoseiSwap 也正式发布了新的市场进程&#xff0c;基于其治理代币 POSE 的 I…

转辙机介绍

简介 转辙机是指用以可靠地转换道岔位置&#xff0c;改变道岔开通方向&#xff0c;锁闭道岔尖轨&#xff0c;反映道岔位置的重要的信号基础设备&#xff0c;它可以很好地保证行车安全&#xff0c;提高运输效率&#xff0c;改善行车人员的劳动强度。 分类 01、转辙机按动作时…

如何做出有价值的知识管理文档?

知识管理文档是企业中重要的资产&#xff0c;它可以帮助企业员工更好地理解业务流程、产品功能、标准操作等信息。如何做出有价值的知识管理文档&#xff0c;满足员工知识需求&#xff0c;提高工作效率&#xff0c;本文将探讨以下几个方面&#xff1a; 一、制定有效的知识管理…

jsp网上鞋城系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 网上鞋城系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5 开发&#xff0c;数据库为Mysql&#xff0c;使用j…