MySQL Basic
一、MySql原理
语句执行流程
如图:
略
- 连接
- MYSQL服务默认监听的端口是3306,客户端连接服务器的方式有很多。可以是同步的也可以是异步,可以是长连接也可以是短连接,可以是TCP也可以是Unix Socket。
- 客户端每产生一个连接或者会话,在服务端都会创建一个线程来处理。MySql会把长时间不活动的连接自动断开,默认是28800秒,8小时
- MySql允许最大的连接数是:151个,最大可以设置成100000
- MYSQL服务默认监听的端口是3306,客户端连接服务器的方式有很多。可以是同步的也可以是异步,可以是长连接也可以是短连接,可以是TCP也可以是Unix Socket。
- 读取缓存
- MYSQL 自带一个缓存模块,默认是关闭的。
- MYSQL 不推荐使用自带的缓存,第一个:是他要求SQL语句必须一模一样中间多一个空格、字母大小写不同都会被认定SQL不一致。第二个:表里面任意的一条数据发生改变,都会到时缓存失效,对大量数据更新的应用,也不合适
- 语法解析和预处理
- 词法解析,就是把一个完整的SQL打碎成一个个单词,记录每个单词的类型,重哪里开始和哪里结束
- 语法解析,根据MYSQL定义的语法规则,根据SQL语句生成一个数据结构,这个数据结构称做:解析树
- 预处理器
- 预处理器会检查生成的解析树,比如,它会检查表和列名是否存在,检查名字和别名,保证没有歧义。
- 预处理后会生成新的解析树
- 查询优化
- 查询优化器就是根据解析树生成不同的执行计划,然后选择一种最优的执行计划。MySQL里面使用的是基于开销的优化器,哪种执行计划开销最小,就选择哪种
- MySQL优化器可以执行哪些优化类型:
- 当我们对多张表进行关联查询时,以哪个表的数据作为基准表
- 有多个索引可以使用时,选择哪个索引
- 执行计划
- 查询执行计划是一个数据结构,MySQL中使用EXPLAIN就可以看到执行计划的信息
- 执行引擎
- 使用执行计划调用api去操作存储引擎,最后把数据返回给客户端
- 存储引擎
- 任何一个存储引擎都有一个frm文件,这个是表结构定义的文件
- 不同存储引擎存放数据的方式也不一样
- 略
- 一张表的存储引擎是在创建表的时候指定的,使用ENGINE关键字
- 常见存储引擎的比较:
- myisam存储引擎包含3个文件,特点:
-
支持表级别的锁
(插入和更新会锁表),不支持事务
- 拥有较高的插入和查询速度
- 存储了表的行数(count的速度更快)
- 适合只读之类的数据分析系统
-
支持表级别的锁
- innodb存储引擎包含2个文件,特点:
- MySQL5.7中默认的存储引擎
- 支持事务,支持外键,因此数据的完整性、一致性更高
- 支持行级别、表级别的锁
- 支持读写并发,写不阻塞读(MVCC)
- 特殊的索引存放方式,可以减少IO,提升查询效率
- 适合经常更新表,存在读写并发或者有事务处理的业务系统
- memory存储引擎包含1个文件,特点
- 把数据存储在内存里面,读写的速度很快,但是数据库重启或者崩溃数据会全部丢失。
- 只合适做临时表
- CSV存储引擎包含3个文件
- 带有逗号的分隔值的文本文件,允许以CSV格式导入或者转储文件,方便与读写相同格式的脚本或者程序之间交换数据
- 不允许空行,不支持索引。格式相通,可以直接编辑,适合在不同数据库之间导入导出
- Archive存储引擎包含2个文件
- 用于存储和检索大量很少引用的历史、存档或者安全审计的信息
- 不支持索引,不支持update和delete
- myisam存储引擎包含3个文件,特点:
MySQL架构分层
略
InnoDB存储引擎的一些原理
缓冲池 Buffer Pool
1. InnoDB设计的一个内存的缓冲区,专属的名字叫Buffer Pool
2. 读取数据时,先判断是不是在这个内存区域内,如果是则直接获取。如果不是则读取后写入这个内存缓冲区;修改数据时,优先写入到Buffer Pool,而不是直接写入磁盘。
3. InnoDB设定了存储引擎从磁盘读取数据到内存的最小单位,叫做页。最小的单位默认是16K
4. 内存的数据页和磁盘的数据不一致时,我们把它叫做脏页,InnoDB有专门的后台线程把Buffer Pool中的数据写入磁盘,每隔一段时间就一次性把多次修改写入到磁盘,这个动作叫刷脏
5. Buffer Pool的作用就是提高读写效率
Redo log
6. 前提因为刷脏不是实时的,如果Buffer Pool里面的脏数据还没刷入磁盘时,数据宕机或者重启了,这些数据就会丢失。这种情况,InnoDB把所有对页面的修改操作写入一个日志文件。这个日志文件就是磁盘的redo log(重做文件)
7. 略
8. <font style="color:#DF2A3F;">疑问:同样是写磁盘,为什么不直接写到db file?为什么要先写到日志再写到磁盘?直接写磁盘(刷盘)是随机IO,而记录日志是顺序IO(连续写的),顺序IO的效率更高。本质上是数据的集中存储和分散存储的区别。先把修改写入日志文件,在保证内存数据的安全性下,可以延迟刷盘时机,进而提升系统的吞吐量。</font>
9. <font style="color:#000000;">redo log的特点:</font>
1. <font style="color:#000000;">redo log是InnoDB存储引擎实现的,并非所有存储引擎都有。支持崩溃恢复是InnoDB的一个特性</font>
2. <font style="color:#DF2A3F;">redo log是记录的是“在某个数据页做了什么修改”,属于物理操作</font>
3. <font style="color:#000000;">redo log 大小是固定的,默认有2个文件:ib_logfile0和ib_logfile1,每个文件大小48M。前面的内容会被覆盖,</font><font style="color:#DF2A3F;">一旦写满就会触发Buffer Pool同步到磁盘</font>
Undo log
10. <font style="color:#DF2A3F;">undo log(撤销日志或回滚日志)记录事务发生前的数据状态</font>,分为insert undo log和update undo log。
11. <font style="color:#DF2A3F;">可以理解undo log记录的是反向操作</font>。<font style="color:#DF2A3F;">如果修改数据记录时出现异常,可以用undo log来实现回滚操作</font>
12. redo log和undo log与事务密切相关,统称为事务日志
MySQL 更新过程
13. 事务开始,从内存(Buffer Pool)或者磁盘(data file)读取包含这条数据的数据页,返回给Server的执行器
14. Server的执行器修改数据页的这一行数据
15. 记录修改前的值到undo log
16. 记录修改后的值到redo log
17. 调用存储引擎接口,记录数据页到Buffer Pool(修改后的值)
18. 事务提交
InnoDB总体架构
19. **Buffer Pool**
1. <font style="color:#DF2A3F;">Buffer Pool缓存的是页面信息,包括数据页、索引页,默认的大小是128M</font>
2. Buffer Pool使用LRU算法来管理缓冲池(链表的表现,不是传统的LRU,分成了young和old区)
3. LRU的List分成两部分,靠近head的叫做new sublist用来存储热数据(我们称作为热区);靠近tail的叫做old sublist(我们称作冷区)
4. 新数据加入到Buffer Pool时,一律先放到冷区。如果一些预读数据没有被用到,会在old sublist(冷区)直接被淘汰。放到LRU list后,如果再次被访问,都把他移动到热区的head。如果热区的数据长时间没有被访问,会被先移动到冷区的head,最后慢慢在tail淘汰
20. **<font style="color:#DF2A3F;">待定</font>**
binlog
1. binlog以事件的形式记录了所有的DDL和DML语句(记录的是操作而不是数据,因此binlog属于逻辑日志)。binlog一般用来做主从复制和数据恢复
2. 和Redo log不一样,binlog文件内容是可以追加的,没有固定大小限制
3. 日志记录顺序
1. 略
4. 上面流程的重点
1. 先记录到内存,再写日志文件
2. <font style="color:#DF2A3F;">先记录redo log日志,分为两个阶段prepare和commit</font>
3. 存储引擎和Server层记录不同的日志,binlog是在Server层记录的
4. <font style="color:#DF2A3F;">先记录redo log,再记录binlog</font>
5. 为什么没要两阶段提交?
二、MySql 索引
数据库索引
1. 是数据库管理系统(DBMS)中一个<font style="color:#DF2A3F;">排序</font>的<font style="color:#DF2A3F;">数据结构</font>,以协助快速查询、更新数据库表中的数据
2. 略 #### 索引的类型
1. InnoDB中索引的类型一共有3种
1. 普通索引:也叫非唯一索引,是最普通的索引,没有任何限制
2. 唯一索引:唯一索引要求键值不能重复。主键索引是特殊的唯一索引,多了一个限制要求键值不能为空
3. 全文索引(fulltext):针对比较大的数据,要解决like查询在全文匹配的时候效率低下的问题,可以创建全文索引,只有文本类型(char、varchar、text)才能创建全文索引
索引存储模型推演
1. **二叉查找树**
1. 左子树的所有节点都小于父节点,右子树所有节点都大于父节点。投影到水平面后就是一个有序的线性表
2. 能够实现快速的查找和快速的插入。但是,在最坏的情况下会退化成链表,时间复杂度O(n)。主要的原因是左右子树深度差太大,不够平衡
3.
4. 略
2. **平衡二叉树(AVL Tree)**
1. <font style="color:#DF2A3F;">左右子树的深度差的绝对值不超过1</font>
2. 他是怎么保证左右子树的深度差不超过1 的呢?AVL Tree会进行<font style="color:#DF2A3F;">左旋和右旋操作</font>
3. 略
4. 略
5. <font style="color:#DF2A3F;">平衡二叉树用于存储索引数据存在问题?</font>
1. InnoDB操作磁盘的最小单位是一页,大小是16KB。平衡二叉树一个节点值存储一个键值+数据+引用,远远达不到16KB的容量。<font style="color:#DF2A3F;">在读取相等的数据下,IO操作比较多,不合理</font>
3. **多路平衡查找树(B Tree)**
1. B Tree就能解决上面的问题
2. <font style="color:#DF2A3F;">B Tree在枝节点和叶子节点同样存储键值、数据地址、节点引用</font>。<font style="color:#DF2A3F;">有一个特点:分叉数(路数)永远比关键字数多1,</font>例如:
3. 略
4. B Tree 在子节点超过定义的最大Max Degree时,会进行分裂和合并。节点的分裂和合并,其实就是InnoDB页的分裂和合并。因此为什么我们不建议在更新频繁的列上建索引,或者不要更新主键
5.
4. **B+ Tree**
1. B Tree 的效率已经很高了,为什么还要使用B+Tree 呢?因为B+Tree有以下特点:
2. 略
3. 特点:
1. <font style="color:#DF2A3F;">关键字的数量和路数是相等的</font>
2. B+ Tree的根节点和枝节点不会存储数据,只有叶子节点才会存储数据
3. B+ Tree的每个叶子节点增加了一个指向相邻叶子节点的指针,形成一个有序的链表结构
4. <font style="color:#DF2A3F;">性能优势</font>:
1. 是B Tree变种,B Tree能解决的问题,B+ Tree也能解决。<font style="color:#DF2A3F;">每个节点存储更多关键字,路数更多</font>
2. <font style="color:#DF2A3F;">扫库,扫表能力更强</font>。<font style="color:#DF2A3F;">如果需要对表进行全表扫描,只需要遍历叶子节点就行</font>
3. B+ Tree的磁盘读写能力相对于B Tree更强,原因是:<font style="color:#DF2A3F;">根节点和枝节点不保存数据,所以一个节点保存更多的关键字,一次磁盘IO加载更多的关键字</font>
4. <font style="color:#DF2A3F;">排序能力更强</font>,因为叶子节点有下一个数据区的指针,数据形成了链表
5. <font style="color:#DF2A3F;">效率更稳定,B+ Tree永远都是在叶子节点拿到数据,所以IO次数更稳定</font>
5. 为什么不用红黑树:
1. 红黑树也是BST树,通过变色和旋转赖保持平衡。
2. 红黑树的特点:
1. 节点分为红色和黑色
2. 根节点必须是黑色
3. 叶子节点都是黑色的NULL节点
4. 红色节点的两个子节点都是黑色(不允许两个相邻的红色节点)
5. 从任意的节点出发,到其叶子节点的路径中都包含相同数量的黑色节点
6. 从根节点到叶子节点的最长路径不大于最短路径的2倍
3. <font style="color:#DF2A3F;">为什么不用红黑树:1、只有两条路 2、不够平衡</font>
6. 红黑树一般只放在内存里面用,例如TreeMap,可以用它来实现一致性哈希
B+ Tree的落地
1. MySQL的数据存储
1. InnoDB有2个文件(.frm和.ibd),MyISAM有3个文件(.frm/.MYD/.MYI)。.frm文件是MySQL中表结构定义的文件
2. MyISAM
1. 一个是.MYD是数据文件,存储数据记录
2. 一个是.MYI是索引文件,存储的是索引。一个索引就会有一颗B+ Tree,所有的B+ Tree都在MYI文件里面。
3. MyISAM中,数据和索引是两个独立的文件,如下图:
4. 略
3. InnoDB
1. InnoDB里面叶子节点直接存储了数据,索引即数据,数据即索引
2. <font style="color:#DF2A3F;">聚集索引(Clustered Index)</font>是一种特殊的索引类型,它决定了数据在磁盘上的物理存储顺序,<font style="color:#DF2A3F;">聚集索引的叶子节点直接包含了表的数据行,而不是指向数据行的指针</font>。
3. <font style="color:#DF2A3F;">InnoDB中如果有主键索引,那么主键索引就是聚集索引</font>。其他索引统一叫做“二级索引”。二级索引的叶子节点存储的是这条记录对应的主键的值。因此,主键索引比二级索引少扫描了一颗B+ Tree(避免了<font style="color:#DF2A3F;">回表</font>)
4. 略
5. <font style="color:#DF2A3F;">没有主键怎么办??</font>
1. 如果我们定义了主键(Primary Key)InnoDB会选择主键作为聚集索引
2. 如果没有显示定义主键,InnoDB会选择第一个不包含NULL值的唯一索引作为主键索引
3. 如果也没有这样的唯一索引,则InnoDB会选择内置的6个字节长的ROWID作为隐藏的聚集索引。
索引的使用规则
2. 索引不是越多越好
3. 创建索引原则:
1. 列的离散度:列的重复值越多,离散度就越低;列的重复度越低,离散度就越高。<font style="color:#DF2A3F;">一般在离散度高的字段建立索引</font>
2. 联合索引最左匹配原则:
1. B+ Tree 是按照从左往右的顺序来建立索引树的,需要把常用的列放在最左边
2. 例如创建:index(a,b,c)相当于创建index(a)/index(a,b)/index(a,b,c)
3. 覆盖索引
1. <font style="color:#DF2A3F;">回表</font>:非主键索引,我们先通过索引找到主键索引的键值,再通过键值查找出索引里面的数据。它比主键索引的扫描多扫描了一棵树,这个过程叫做回表
2. 在二级索引中,不管是单列索引或者联合索引,如果select的数据列从索引中就能够取得,不必从数据区读取,这时候使用的索引就叫**<font style="color:#DF2A3F;">覆盖索引</font>**。覆盖索引减少了IO次数,减少了数据的访问量
4. <font style="color:#DF2A3F;">索引条件下推(ICP)</font>
1. <font style="color:#DF2A3F;">ICP默认开启,不需要认为干预</font>。<font style="color:#DF2A3F;">只适用于二级索引</font>,ICP的目标是减少访问表的完整行的读数量从减少IO操作,<font style="color:#DF2A3F;">意思是把过滤的动作在存储引擎做完,而不需要到Server层过滤</font>。
2. 索引的比较是在存储引擎进行的,数据记录的比较是Server层进行。
3. ICP,存储引擎过滤时的EXPLAIN