MySQL 表和索引优化实战|学习笔记(一)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 快速学习 MySQL 表和索引优化实战

开发者学堂课程【MySQL 实战进阶MySQL 表和索引优化实战】学习笔记,与课程紧密联系,让用户快速学习知识

课程地址:https://developer.aliyun.com/learning/course/83/detail/1310


MySQL 表和索引优化实战


内容介绍:

一、主键索引

二、二级索引

三、数学分析

四、索引的作用

 

一、主键索引

本课程和大家分享 RDS for MySQL 表和索引的优化经验。

作为数据库的使用者来说,避免不了会接触两个概念,一个是表,一个是索引。在日常的思维中表是用来存储表中的数据,索引一般是用来加速查询访问。

RDS for MySQL innodb 引擎下的数据真正物理组织,是怎么组织的?首先有这样一张表

image.png

它的主键是一个 mp  四个字节的整形的 id 作为主键,后面跟着一个单字符的clumn1,还有一个 int 类型的 column 2,单字符的 column 3。在c1字段上会有一个索引,就是一个很简单的一张表。

下面看它的数据是如何组织的。

 image.png

首先说明一下在 innodb 引擎下实际上数据是存储在主键中的,数据是通过主键来物理组织的。它跟 airkong 本身默认的堆表不一样,airkong 本身默认创建的表如果不特定指定的话,是一个堆表,它真的有一个对象数据结构堆的数据结构来存储数据,同时主键是另外一个数据结构,是真的是这样两份的数据。对于 MySQL innodb 的引擎,它本身的数据是存储在主键的叶子节点中的,column1column2column3这三列数据都存储在主键的叶子节点中。

主键本身从数据结构存储的数据结构上来看是 B+TRee,说明一下 B+TRee 本身是一个 b 树,b 指的是 balance TRee,就是平衡树,完整的名字叫做多路平衡树。多路平衡树本身是一个平衡树,而不是binary TReebinary TRee 是一个二叉树,这是作为数据库 DBA 的基本功。多路平衡树和二叉树的区别在于二叉树只有左分支和右分支,而且不限定左分支和右分支的深度,也可以理解为树的高度,不限定左分支和右分支的高度必须一致的;多路平衡树首先是一个平衡树,

image.png

最上面的节点叫做根节点,从根节点到任何一个叶子节点,通走的节点数是要一致的,树高从任何一个维度来看,从任何一个叶子节点到根,从根到任何一个叶子节点必须得是一致的,就是左右是平衡的。多路的意思是每一个节点的分支节点也好,根节点也好,下面可以有多个子节点,而不只限定只有左节点、右节点。

同时在整个的结构里面,如果对 oracle 比较熟,oracle 有一个叫 block size,在 oracle 体系中对于每一个存储的基础来源叫做block

MySQL 当中叫做叶,叫做配置,实际上是一样的概念。在 MySQL 里面,如果不特意指定的话,默认16KB 作为叶。如果从磁盘上访问一行数据,哪怕需要访问一个字节,也要这16 KB 的磁盘块,注意这是一个区的,不是真正的这个磁盘的,大小磁盘可能是4KB 的。四个4 KB 的组成一个16KB 的逻辑块,需要读16 KB 的数据到内存中。

这个结构里面,数据组织结构之后有几个关键的地方,第一个是数据是存储在主键中的,创建这张表的时候,最佳时间就是必须要显示的定义主键。

不显示定义主键的话,会出现两种情况,一种情况是在做数据传输的时候,没有办法决定这张数据是否重复,是否是唯一的,主键的定义是非空、唯一。另外一种情况是当 RDS for MySQL 的备份还原到线下的开源版本中,没有主键的表,读取的时候会发现字段对不上的情况。因为内部阿里的 sql ,实际上 RDS for MySQL MySQL  的生态体系中是正式的阿里 sql,是一个 MySQL  的分支。对于这个分支来说,为了避免出现没有定义主键,导入了很多问题,如果这张表不显示定义主键,默认的会隐式的给它增加一个字段,这个字段对应用和用户来说都是不可见的,但是把物理备份还原到本地的时候,会发现访问这张表多出一个字段,这个隐式的字段会导致恢复的时候这张表不可访问。

所以最佳时间,既然是一棵树,数据要存储在树里面,存储在主键里面,就要显示定义主键。

image.png

这张表每个数据块的大小都是16 KB,这个分支节点也是16 KB,是不是这个分支节点下胯的节点数越多,这棵树可以越扁,就是树高可以越小。树高是从根节点到叶子节点中间走过多少配置,就是它的树高,树高跟性能相关。

日常访问的表,如果不是非常频繁访问的表,而且内存容量比较有限的情况下,根和分支节点都是在内存中的。但是需要访问数据块的话,需要从根访问到分支,再到叶子节点。

如果树高很高的话,而且内存很紧张,分支如果不在内存中的话,需要把分支节点先读进来,在到读叶子节点。数高越高,需要读的16 KB的块数就越多,也就是说,同样访问一行数据,需要比树高小的索引,要访问额外多的数据量,这种承载IO本身紧张的资源的情况下,就会导致查询更慢。因为访问数据花费的代价要比别人多,树高越高,访问叶子节点的代价就越大。这导致了在块的尺寸固定的情况下,如果里面可呆的条目数越多,下胯的节点数就越多,节点数越多,就可以让叶子节点数量在固定的情况下,已知的情况下,树高就越小,这个数据越扁平。

大家可以想一想,一个公司组织架构里面,如果中层领导越强,下面呆的部门越多,整个公司的组织结构会越扁平化。

第三件事情,在块的尺寸固定的情况下,这里面的条目数越多,树高越小,访问数据的代价就低。这取决于本身对主键的数据类型是有要求的,如果在 int 类型四个字节,big int 八个字节,如果这是一个个 ychar,但是它会保留固定的长度。如果使用一个字符串,是在 utf8 这个字符集的情况下,像column 1 这个类型,utf8 至少需要三个字节,utf8mb4 需要4个字节,所以最佳的时间就是主键尽量是 int 或者是 big int,最终整形。因为它本身很小,四个字节、八个字节,通常情况下,一个16 KB 的块能放几百个这样的条目。正常情况下,能放几百个条目,树高就很容易控制在三或者四,三是常见的,四已经不小了,三或者四这个水平量。或者是数据的分析,这是第三件事情。

第四件事情,它是一个平衡树。平衡树的要求就在于左边的分支,从根到任何一个叶子节点,树高都要固定。当这棵树不断的被修改,不断的增删改的情况下,这棵树实际上是在时刻变化的。为了保证根始终到树高是一致的,保证树跟着数据修改随时在变化,这个时候会带来一个问题,如果每次插入的数据都是在中间,而这棵树本身已经很大,一亿行记录了一张表,每次插入的数据都不是可预期的,都是随机的插到树的不同的地方。是不是经常需要把链表打开,把结构打开,到内存里把链表打开,然后把它重新组织成需要的合理的树,然后再拼在一起。这个对写的代价会非常大,尤其对于 insert 来说,写的代价非常大。

因为每次插入的数据都不是可预期的,不是朝着一个方向来变化的,每次都是随机的,就会导致写入的 rt 响应时间变得不可预期,总体指令会比较高。第四件事情就是主键除了数据类型有要求以外,建议用 or to improvement 正向递增,或者使用 SQL 字段,比如说有 RDS polar x 的场景下,或者是 SQL 引擎的情况下,sql 或者or to improvement 保证它单向递增,保证每次写入或插入的操作性能比较一致,避免总要把一棵树拆开,再拼在一起。这是这张表在做表设计的时候,它本身是一个主键,根据主键存储的物理存储的数据结构,引出了四个。第一个是必须定义主键,第二个主键数据类型要尽量的小,第三个介绍了树高、16 KB 的块,第四个auto increment 要正向的去插。

 

二、二级索引

MySQL key index 是同义词,除了主键以外的索引都称之为二级索引,看下图所示的索引

image.png

 

这个索引跟主键一样,也是 B+TRee 索引,它下面的每一个链表,跟叶子节点之间是双向链表,也是一颗多路平衡树。但是它跟 oracle 本身在设计上有一点不一样,c1 字段做了一个索引,但实际上在存储值的时候,因为数据是存储在主键中的,所以数据在停止的时候没有必要放数据的真正的物理地址,在 oracle 里放的是物理地址,但是在 MySQL 里面这里直接放的是主键的值,因为知道主键的值,就能唯一的定位到这行记录。实际上,虽然在这里放了c1,但是真正在存储的时候是把叶子节点值存起来的,反过来也就是说,主键的数据类型,导致了存储长度要尽量的小,如果主键真的很大的话,会出现问题。

补充一下,主键除了之前说的单向递增数据类型要小以外,比如说像 uuid 这种不建议做主键,因为太长了。如果字段太长的话,磁盘块里的方子会很小,数额会变得很臃肿。存储相同的数据量索引会占更大的空间,这对 IO 来说会产生很大的影响,相同硬件条件下比别人要慢,访问数据速度要慢,因为开销大,成本高。

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
Oracle 关系型数据库 MySQL
【mysql】—— 表的内连和外连
【mysql】—— 表的内连和外连
|
1月前
|
存储 关系型数据库 MySQL
【mysql】—— 表的增删改查
【mysql】—— 表的增删改查
|
24天前
|
存储 SQL 关系型数据库
【MySQL】4. 表的操作
【MySQL】4. 表的操作
21 0
|
27天前
|
SQL 关系型数据库 MySQL
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
96 0
|
22天前
|
存储 关系型数据库 MySQL
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
|
22天前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
|
1天前
|
SQL 关系型数据库 MySQL
不允许你不知道的 MySQL 优化实战(一)
不允许你不知道的 MySQL 优化实战(一)
|
3天前
|
关系型数据库 MySQL 中间件
【MySQL实战笔记】07 | 行锁功过:怎么减少行锁对性能的影响?-02 死锁和死锁检测
【4月更文挑战第19天】在高并发环境下,死锁发生在多个线程间循环等待资源时,导致无限期等待。MySQL中,死锁可通过`innodb_lock_wait_timeout`参数设置超时或`innodb_deadlock_detect`开启死锁检测来解决。默认的50s超时可能不适用于在线服务,而频繁检测会消耗大量CPU。应对热点行更新引发的性能问题,可以暂时关闭死锁检测(风险是产生大量超时),控制并发度,或通过分散记录减少锁冲突,例如将数据分拆到多行以降低死锁概率。
19 1
|
6天前
|
SQL 关系型数据库 MySQL
Python与MySQL数据库交互:面试实战
【4月更文挑战第16天】本文介绍了Python与MySQL交互的面试重点,包括使用`mysql-connector-python`或`pymysql`连接数据库、执行SQL查询、异常处理、防止SQL注入、事务管理和ORM框架。易错点包括忘记关闭连接、忽视异常处理、硬编码SQL、忽略事务及过度依赖低效查询。通过理解这些问题和提供策略,可提升面试表现。
26 6
|
13天前
|
存储 关系型数据库 MySQL
【MySQL实战笔记】 04 | 深入浅出索引(上)-02
【4月更文挑战第9天】InnoDB数据库使用B+树作为索引模型,其中主键索引的叶子节点存储完整行数据,非主键索引则存储主键值。主键查询只需搜索一棵树,而非主键查询需两次搜索,因此推荐使用主键查询以提高效率。在插入新值时,B+树需要维护有序性,可能导致数据页分裂影响性能。自增主键在插入时可避免数据挪动和页分裂,且占用存储空间小,通常更为理想。然而,如果场景仅需唯一索引,可直接设为主键以减少查询步骤。
15 1
【MySQL实战笔记】 04 | 深入浅出索引(上)-02