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

mysql知识总结 基础篇

Mysql知识总结

    • 1. 执行一条sql语句 期间发生了什么?
      • 1. 如何查看mysql服务被多少个客户端链接了
      • 2. 空闲链接会一直闲置嘛?
      • 3. mysql的链接数量有限制嘛?
      • 4. 我们如何知道mysql要使用哪个索引
      • 5. 什么是覆盖索引
    • 2. MySQL 一行记录是怎么存储的?
      • 1. mysql的数据存储放在哪个文件?
      • 2. 表结构的空间是什么样的
      • 3. innodb的默认行格式 是什么
      • 4. 记录格外的数据
      • 5. 记录真实的数据
      • 6. varchar(n)中的n最大取值
      • 7. 行溢出后 mysql是如何处理的

本文是阅读 小林coding 后的读书笔记

原文可以点击上面超链接到达

也可以直接百度搜索 小林coding

1. 执行一条sql语句 期间发生了什么?

这道题目其实问的就是mysql的执行流程嘛

在这里插入图片描述

我们可以看到mysql分为两层嘛 一个是server层 一个是存储引擎层

server层复杂负责链接以及sql语句的分析 执行

存储引擎层负责数据的存储和提取

下面我们一步步来看它是怎么执行的嘛

第一步 建立链接

首先第一步是链接 我们mysql的客户端输入账号密码会链接mysql的服务器嘛 它底层是基于tcp协议 如果链接失败就会报错的

然后如果账号密码都没有问题 mysql就会保存它的权限并且管理起来 后续用户进行的任何操作都会基于该保存的权限进行操作

总结下连接器的工作

  1. 和客户端三次握手建立链接
  2. 验证账号密码是否正确
  3. 读取用户的权限 并且后续操作都基于此权限

第二步 查询缓存

之后第二步就是查询缓存 查询缓存实际上就是分析下当前的sql语句 看啊可能之前有没有执行过 如果执行过把缓存的数据返回给连接器 之后返回给客户端嘛

但是这个操作实际上是很鸡肋的 缓存要在多次使用同一条语句的时候才会有比较大的作用

但是一旦表进行了更新操作 这个缓存就会被清楚 相当于缓存了个寂寞

所以说mysql的8.0版本直接将这一步给删除掉了

对于之前的版本 我们也可以通过设置参数来解决这个问题

第三步 解析sql

在正式执行sql语句之前 解析器会对于sql语句进行解析 包括语法分析 然后词法分析

词法分析就是将其中的关键字和非关键字提取出来嘛

语法分析就是分析你这个sql语句是否符合sql语法嘛 如果符合的话 就会简历一个语法树

如果我们的sql语句不对 就会在这个阶段报错

第四步 执行sql

它分为预处理 优化 执行

预处理器

预处理阶段会做两件事

  1. 判断我们要查询的表是否存在
  2. 把 * 替换为表中的各列

优化器

优化器的主要作用就是将sql语句的执行计划确定下来 比如说表里面有多个索引 然后它会确定用哪个索引

执行器

执行器执行的时候会和存储引擎交互 从存储引擎读取数据返回给连接器

1. 如何查看mysql服务被多少个客户端链接了

我们可以使用show processlist来查看 mysql服务被多少个客户端链接了

2. 空闲链接会一直闲置嘛?

不会 我们有一个参数 show variables like 'wait_timeout'; 来查看空闲时间 如果超过了这个时间就会被断开链接

如何修改这个参数

  1. SET SESSION wait_timeout = 600;
  2. SET GLOBAL wait_timeout = 600;
  3. 永久修改的话 可以修改配置文件

3. mysql的链接数量有限制嘛?

有的 我们可以使用 show variables like 'max_connections'; 来查看这些链接数量闲置

mysql和http一样 也有长短链接的概念 区别如下 我们使用长连接可以减少过程中链接和断开的过程

但是我们维护长连接也会消耗一定的资源嘛 所以说我们也要想办法去解决这个问题嘛

解决问题的方式有两种

  1. 定期的去断开链接
  2. 客户端自己主动重制链接 调用 mysql_reset_connection()

4. 我们如何知道mysql要使用哪个索引

我们可以使用 explain 加在一条sql语句之前 来查看sql语句使用了什么索引嘛

它里面有一行是key 如果是null则说明无任何索引 如果是primary则是主键

在这里插入图片描述

如果说我们一条查询语句有两个索引 那么编译器就会选择最佳的索引

5. 什么是覆盖索引

覆盖索引是指表中包含了查找所需要的所有字段 不需要再回表查询了

2. MySQL 一行记录是怎么存储的?

1. mysql的数据存储放在哪个文件?

mysql的数据自然是保存在磁盘中嘛 关于具体保存在哪里 这个要根据存储引擎来区分

以为innob为例 我们每创建一个database数据库 他就会创建一个名叫datebase的文件

我们每创建一个表 实际上就是再datebase目录中再创建一个文件(表名)

当我们进入这个目录的时候我们会发现里面有三个文件

分别是

  1. db.opt
  2. name.frm
  3. name.idb

其中opt文件用来存储默认字符集和校验规则

frm文件用来保存表结构的元数据

而文件的表数据则会保存在 ibd 文件中

2. 表结构的空间是什么样的

表结构的空间如下

在这里插入图片描述

表由许多段组成 段由许多区组成 区由许多页组成 页里面有许多行数据

我们的每条记录就是一行 每行记录根据不同的格式有不同的存储结构

虽然说我们的存储是根据行来存储的 但是如果根据行读取的话效率就太低了 所以说innodb数据是根据页来存储的 页的大小有16kb

页是管理的最小单元 也就是说每次最少从磁盘中读取16kb的数据

我们都知道innodb是用b+数来组织存储数据的

B+树的每一层都是通过双向链表链接起来的 如果以页来分配单位的话 那么两个相邻的页的物理位置不是连续的 可能会离得非常远 那么磁盘查询的时候可能就会有大量的随机IO 而随机IO是非常慢的

如何解决这个问题呢? 很简单 让他们的物理空间也连续就好了

所以说当表中数据量很大的时候 就不以页来分配单位了 而是按照区来分配单位 区的大小是1mb左右 大概能容纳64个页

表空间是由段组成的 而段由多个区组成 段一般分为下面几个部分

  1. 索引段 存放B+树非叶子节点的区的集合
  2. 数据段 存放B+树叶子节点的区的集合
  3. 回滚段 存放的是回滚数据的区的集合

3. innodb的默认行格式 是什么

innodb的默认行格式为 compact

在这里插入图片描述

我们可以看到 一条记录可以分为两个部分 记录额外的信息和记录真实的数据

4. 记录格外的数据

记录额外的信息

我们首先来看记录额外的信息 它分为三个部分

  1. 变长字段长度列表

我们存储数据的时候 需要把这个数据存储的大小给存起来放到变长字段长度列表里面 读取数据的时候才能根据这个变长字段长度列表去读取对应长度的数据

假设我们有这三条记录

其中name和phone是变长字段 长度为11

在这里插入图片描述

接下来我们分别看他们是如何存储的

name的真实数据大小是1 phone的真实数据大小是3

在这里插入图片描述
他们是按照逆序存放的 这里涉及到一个mysql调优的问题 在下面

行2和行1类似

行3和行1的区别主要是phone值是none null是不会存放在行格式记录的真实数据里面 所以变长字段里面也不会有(置0处理)

mysql调优

msql 有一种潜规则优化,就是靠前的字段有更好的访问性能。

这是mysql对于用户使用策略的一种假设,就是假设用户会更频繁的使用靠前的字段。并且这种策略更符合人的直觉。

优化手段有很多,我这里介绍一种,对于变长字段长度的反向存储优化

在一个行里面变长资源是反向存储的 因为这样更容易让这些数据和对应的真实数据同时存放在一个cpu cauch line中 这样子可以提高cpu canch的命中率

设计库函数是有艺术成分在里面的。
因为有很多trade off的事情需要考虑。

就好比操作系统设计内存分配的页表管理有很多种策略,先进先出还是先进后出等等。
这种行为比较重要的可以通过统计数据来得出。

比较轻度的可以基于一种假设去设计。只要这种假设是符合直觉的,一般都是合理的

再好的库函数,也会在面临不同策略下有不同的优势。
库函数sort再快,你针对单独case优化也可能超过库函数

每个数据库的行格式 都有变长数据列表嘛

不是的 假如说我们没有变长字段的话行格式里面就不会有了

  1. Null值列表

表中的某些列可能会存储NULL值 如果把这些NULL值都放到记录真实数据中会比较浪费空间 (其实Linux中的很多地方也用到了这种涉及 存在和不存在只需要一个位就可以)

如果存在NULL值 则每个列对应一个二进制比特位 按照顺序逆序存放

在这里插入图片描述

每个数据库的行格式都必须要有NULL值列表嘛

NULL值不是必须的 当数据表的字段都定义成NOT NULL的时候 可以至少节省1字节的空间

NULL值列表是固定一字节嘛 如果有一条记录有九条记录没有设置为not null呢?

如果有九条记录的话就null这一字段就对应为2个字节 以此类推

  1. 记录头信息

记录头信息中的内容很多 这里列举几个

  1. delete_mask 表示这条数据是否被删除 我们删除一条数据的时候 并不会真正的删除记录 而是会将这个记录的delete_mask标记为1
  2. next_record 下一条记录的位置

5. 记录真实的数据

在这里插入图片描述

我们可以看到 记录真实数据中 除了我们定义的字段 还有额外的三个字段

  1. row_id

如果说我们没有定义主键或者唯一约束列 那么innode引擎就会生成row_id列

这个列不是必须的 大小为6个字节

  1. trx_id

表示事务的id 表示数据是由哪个事务生成的 它是必须的 占用六个字节

  1. roll_pointer

记录指向上一个版本的指针 大小为7个字节

6. varchar(n)中的n最大取值

这里我们要知道一个概念 除了隐藏列和记录投信息列之外 所有列加起来不超过65535字节

知道了这个前提之后我们再去推算 varchar(n)中n的最大取值

前面我们知道了一行记录最大的存储值是65535字节 那么我们使用varchar(65535) 是否可以创建成功呢?

答案是否定的

在这里插入图片描述

因为我们这里还有两个列的长度没有进行计算

  1. 变长字段长度列表
  2. null值列表

变长字段列表 当允许存储的列表小于255字节 用一个字节表示 大于255用2个字节表示

null值列表占用空间为1字节 变长字段长度列表为2字节 所以说实际上最大的大小为65532字节

7. 行溢出后 mysql是如何处理的

我们知道mysql中交互的基本单位是页 页的大小是16kb 而65535字节是大于16kb的

这个时候一个页存储不了一行的记录 此时就会发生行溢出

当发生溢出的时候在记录真实数据处会保存该列的一部分数据 并且用20字节指向溢出页

在这里插入图片描述

相关文章:

  • Light RPC:一款轻量高效的Java RPC框架实践指南
  • vscode Colipot 编程助手
  • 【CF】Day26——Teza Round 1 (Codeforces Round 1015, Div. 1 + Div. 2) CD
  • UE5学习笔记 FPS游戏制作44 统一UI大小 sizeBox
  • 关于OEC/OEC-turbo刷机问题的一些解决方法(2)——可能是终极解决方法了
  • day24学习Pandas库
  • k8s核心资源对象一(入门到精通)
  • 3D激光轮廓仪知识整理(待补充)
  • browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,告诉您的计算机该做什么,它就会完成它。
  • 大模型论文:Improving Language Understanding by Generative Pre-Training
  • windterm终端软件使用
  • React-Markdown 组件底层实现原理详解
  • 服务异常挂掉问题:java invoked oom-killer
  • 数字三角形(dfs+动态规划)通过率未达100%
  • 第三次PID状态机
  • 评价区动态加载是怎么实现的?
  • 【AI学习】初步了解Gradio
  • Motionface MFvector照片一键转矢量工具使用教程
  • LeetCode算法题(Go语言实现)_34
  • 排序扩展-文件递归排序(外排序)
  • 世卫大会中国代表团:中国深入参与全球卫生治理,为构建人类卫生健康共同体贡献中国力量
  • 坐标大零号湾科创策源区,上海瑞金医院闵行院区正式启动建设
  • 福建、广西等地有大暴雨,国家防总启动防汛四级应急响应
  • 北京韩美林艺术馆党支部书记郭莹病逝,终年40岁
  • 对谈|“大礼议”:嘉靖皇帝的礼法困境与权力博弈
  • 商务部召开全国离境退税工作推进会:提高退税商店覆盖面,扩大入境消费