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

什么是网站集约化建设运用虚拟机建设网站

什么是网站集约化建设,运用虚拟机建设网站,黄浦企业网站制作,闲鱼搭建网站谣言 互联网上有传言说我们应该避免在单个 MySQL 表中有超过 2000 万行。否则,表的性能会下降,当它超过软限制时,你会发现 SQL 查询比平时慢得多。这些判断是在多年前使用HDD硬盘存储时做出的。我想知道在2023年对于基于SSD的MySQL数据库来说…

谣言

互联网上有传言说我们应该避免在单个 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.yayakq.cn/news/571149/

相关文章:

  • 本人想求做网站网站建设页面页脚怎么设置
  • 泰州商城网站开发网上做家教兼职哪个网站
  • 网站开发案例谷歌seo是什么意思
  • 合肥宣传网站苏州个人网站建设
  • 网站友情链接怎么样做跳转网站代码
  • 网站可以做怀孕单吗房地产网站建设方案
  • 网站登录系统源码上海工信部网站
  • 2017网站seo如何做免备案主机
  • 家用电脑怎么做网站服务器青岛做网站优化公司
  • 做视频网站需要多大空间网站界面设计的发展趋势
  • 优质的网站自助建站网站要不要备案
  • iis 7.0 搭建网站贵阳市住房建设局网站
  • 婚恋网站女孩子做美容哪里有免费的网站模板下载 迅雷下载 迅雷下载软件
  • 一个很好的个人网站开发个人域名备案 网站名称
  • 网站如何接广告低成本网站制作
  • 建站用帝国还是wordpress网站建设的具体布局
  • 做新网站 备案证明交接外链建设的方式有哪些
  • 淄博网站seo公司seo快速优化报价
  • 做网站常用图标优秀设计作品的网站
  • 广州网站建设专业乐云seo手机自己做网站吗
  • 网站设计开发中的具体步骤百度关键词优化工具
  • 中国十大品牌网站怎么制作免费网站
  • 哈尔滨企业网站制作wordpress 怎么上传视频
  • 沈阳做网站比较好的公司培训教育类网站模板下载
  • 网站添加漂浮二维码怎么做软件界面设计教程
  • 织梦怎么做淘客网站如何制作自己的网址教学视频
  • 前端 网站开发 常见功能实现做点小本意 哪个网站拿货便宜点
  • php做直播网站做网站过程视频
  • seo资料站西安公司网站制作价格
  • 中关村在线网站的建设小学校园网站怎么建设