【学习笔记】Mysql45讲 Part1

Mysql1-8讲

由文章整体逻辑——>文章注意要点——> 总结

01 | 基础架构:一条SQL查询语句是如何执行的?

1 用户由登录,到一个查询语句的执行过程是怎么样的?

2 短连接?长连接?
短连接是执行几次就断开;长连接是一直使用的通一个连接

3 为什么使用长连接?为什么要定时超时断开,或通过重新初始化?
连接较为复杂——建议使用长连接。
长连接导致缓存过大

1.1 连接器

1.2 查询缓存

1.3 分析器

1.4 优化器

1.5 执行器

02 | 日志系统:一条SQL更新语句是如何执行的?

1 binlog 和 redo log的理解
2 图中两阶段提交——为了让两份日志之间的逻辑一致

2.1 binlog(归档日志) Serve层

逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1
binlog 是可以追加写入的

2.2 redo log(重做日志)引擎层 ——保证 MySQL 异常重启之后数据不丢失。

物理日志,记录的是“在某个数据页上做了什么修改
redo log 是循环写的,空间固定会用完

03 | 事务隔离:为什么你改了我还看不见?

总结:
1、务的特性:原子性、一致性、隔离性、持久性

2、多事务同时执行的时候,可能会出现的问题:脏读、不可重复读、幻读

3、事务隔离级别:读未提交、读提交、可重复读、串行化

4、不同事务隔离级别的区别:
读未提交:一个事务还未提交,它所做的变更就可以被别的事务看到
读提交:一个事务提交之后,它所做的变更才可以被别的事务看到
可重复读:一个事务执行过程中看到的数据是一致的。未提交的更改对其他事务是不可见的
串行化:对应一个记录会加读写锁,出现冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行

扫描二维码关注公众号,回复: 13124832 查看本文章

5、配置方法:启动参数transaction-isolation

6、事务隔离的实现:每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。

7、回滚日志什么时候删除?系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志会被删除。

8、什么时候不需要了?当系统里么有比这个回滚日志更早的read-view的时候。(读操作产生视图,当这个事务结束后该视图删除,那么在这个视图后的回滚日志可以删除,因为已经没有谁会驱动当前版本的数据执行回滚到删除的那个视图版本了)

9、为什么尽量不要使用长事务。长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还占用锁资源,可能会拖垮库。

10、事务启动方式:一、显式启动事务语句,begin或者start transaction,提交commit,回滚rollback;二、set autocommit=0,该命令会把这个线程的自动提交关掉。这样只要执行一个select语句,事务就启动,并不会自动提交,直到主动执行commit或rollback或断开连接。

11、建议使用方法一,如果考虑多一次交互问题,可以使用commit work and chain语法。在autocommit=1的情况下用begin显式启动事务,如果执行commit则提交事务。如果执行commit work and chain则提交事务并自动启动下一个事务。

思考题:

在开发过程中,尽可能的减小事务范围,少用长事务,如果无法避免,保证逻辑日志空间足够用,并且支持动态日志空间增长。监控Innodb_trx表,发现长事务报警。

3.1 首先,隔离性与隔离级别

3.2 然后,事务隔离的实现

  • 回滚操作
  • 回滚日志的删除

3.3 最后,事务的启动方式

04 | 深入浅出索引(上)

总结:
1.索引的作用:提高数据查询效率

2.常见索引模型:哈希表、有序数组、搜索树

3.哈希表:键 - 值(key - value)。

4.哈希思路:把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置

5.哈希冲突的处理办法:链表

6.哈希表适用场景:只有等值查询的场景

7.有序数组:按顺序存储。查询用二分法就可以快速查询,时间复杂度是:O(log(N))

8.有序数组查询效率高,更新效率低

9.有序数组的适用场景:静态存储引擎。

10.二叉搜索树:每个节点的左儿子小于父节点,父节点又小于右儿子

11.二叉搜索树:查询时间复杂度O(log(N)),更新时间复杂度O(log(N))

12.数据库存储大多不适用二叉树,因为树高过高,会适用N叉树

13.InnoDB中的索引模型:B+Tree

14.索引类型:主键索引、非主键索引
主键索引的叶子节点存的是整行的数据(聚簇索引),非主键索引的叶子节点内容是主键的值(二级索引)

15.主键索引和普通索引的区别:主键索引只要搜索ID这个B+Tree即可拿到数据。普通索引先搜索索引拿到主键值,再到主键索引树搜索一次(回表)

16.一个数据页满了,按照B+Tree算法,新增加一个数据页,叫做页分裂,会导致性能下降。空间利用率降低大概50%。当相邻的两个数据页利用率很低的时候会做数据页合并,合并的过程是分裂过程的逆过程。

17.从性能和存储空间方面考量,自增主键往往是更合理的选择。

思考题:
如果删除,新建主键索引,会同时去修改普通索引对应的主键索引,性能消耗比较大。
删除重建普通索引貌似影响不大,不过要注意在业务低谷期操作,避免影响业务。

4.1 首先,常见的索引结构

  • 哈希表
  • 有序数组
  • 搜索树

4.2 然后,InnoDB 的索引模型(B+树)

哈希表能快速找到数据,但是不支持范围查找,有序数组支持范围查找,但是不支持随机插入,B+树俩者都支持。

  • 1.在 InnoDB 中,每一张表其实就是多个 B+ 树,即一个主键索引树和多个非主键索引树。
    (主键索引的value是行数据,非主键索引的value是主键的值)

2.执行查询的效率,使用主键索引 > 使用非主键索引 > 不使用索引。 (具体结合场景)

3.如果不使用索引进行查询,则从主索引 B+ 树的叶子节点进行遍历。

  • 基于主键索引和普通索引的查询有什么区别?(普通索引“回表”)

4.3 最后,索引维护

  • ”尽量使用主键查询“原则
  • 为了方便索引的维护,一般使用自增主键
    在一些事务下(或者没有二级索引)使用唯一主键

05 | 深入浅出索引(下)

5.1 覆盖索引

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

  • 对比:
    (1)Select * from T where k between 3 and 5 由k对应的value找ID,再找数据(需要回表)

(2)Select ID from T where k between 3 and 5 索引K下直接就是ID值,不需要回表

在(2)这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。

5.2 前缀索引

例如索引是key index (a,b,c). 可以支持a a,b a,b,c 3种组合进行查找,但不支持 b,c进行查找。

5.3 索引下推

利用二级索引(默认与主键形成联合索引)对回表的过程中进行限定,减少回表次数

06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?

6.1 全局锁(对整个数据库实例加锁——对全库逻辑备份)

  • 可以使用一致性视图(”回滚“那块),可以备份当时的数据库,并且该数据库用户也可以进行一系列操作。(一致性读是好,但前提是引擎要支持这个隔离级别)——用锁的原因
  • 使用全局锁——库只读

6.2 表级锁

  • 表锁

    • lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象(不仅仅锁了别人,还锁了自己——事务提交/可以客户端断开时释放)
  • 元数据锁(meta data lock,MDL)

    • 访问一个表的时候会被自动加上
      (防止遍历一个表中的数据时,而执行期间另一个线程对这个表结构做变更)
    • 对于一个频繁使用的表,施加MDL操作——用户使用堵塞问题的产生和解决?!

07 | 行锁功过(引擎自己实现):怎么减少行锁对性能的影响?

7.1 从两阶段锁说起

  • 行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
  • 由用户买电影票引出来的锁问题(尽量将并发度高的行,放在事务的最后进行执—减少等待时间 eg:312)

1 从顾客 A 账户余额中扣除电影票价;
2 给影院 B 的账户余额增加这张电影票价;
3 记录一条交易日志。

7.2 死锁和死锁检测

  • 死锁:当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态

解决的一种策略是,直接进入等待,直到超时。

  这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。

- 解决的另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。


  将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
  • 两种处理

    • 第一种时间长,难以接收;第二种,检测成本大
    • 可以:确保事务不出现死锁/服务端控制并发度/行的逻辑设计

08 | 事务到底是隔离的还是不隔离的?

8.1 事务的启动起点时间判断

  • begin/start transaction 在执行第一个操作 InnoDB 表的语句,事务才真正启动。
  • start transaction with consistent snapshot 立即启动。

8.2 “快照”在 MVCC 里是怎么工作的?(事务隔离的具体实现)

  • 隔开的原因:对于多个事务同时对同一张表进行操作的时候,为了避免数据幻读等——出现了多版本控制MVCC
  • 以下就是一个行记录被多个事务更新后的状态。
    对于RR级别,在事务开始的时候,多个事务依次产生所属自己的一致性视图(一致性视图等只是针对查询语句),视图间互补干扰(更改数据除外!)
  • 可重复读级别下,每个事务是独立的——事务B出的结果 应该是1才对,为什么是3?
    因为“当前读”——读数据时读原始的,但是对于修改数据是修改最新的数据!
  • 事务 B 的视图数组是先生成的,之后事务 C 才提交,不是应该看不见 (1,2) 吗,怎么能算出 (1,3) 来?
    如果事务 B 在更新之前查询一次数据,这个查询返回的 k 的值确实是 1
    这个结果也和上面一样,原因是B是当前读,只有C的锁释放后——事务B才能继续操作!

8.3 对于事务隔离总结

有些是一直下来就一个快照!有些是一个语句一个快照!有些是一个commit一个快照!(对应隔离级别吧)

  • 对于可重复读: 查询只承认在事务启动前就已经提交完成的数据;
    对于读提交: 查询只承认在语句启动前就已经提交完成的数据;
    对于当前读: 总是读取已经提交完成的最新版本

8.4 undo log 在哪呢?

  • 对应8.2第一张图中的绿色虚线!
    根据事务的生成时间,对应事务会生成一系列的版本号(对应着这事务原数据的需改变化),当事务要rool时,根据这版本号逆退出先前数据
  • InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/The_dream1/article/details/115259724