极客时间之MySQL实战45讲个人理解与总结

前言:感谢分享的极客林晓斌老师,文章二刷中,记录下自己的理解。

1.Innodb引擎更新

Server层binlog与存储引擎层redolog(innodb特有)。
操作记录以WAL机制写入redo log并更新至内存,2阶段提交确保crash-safe。可以看出:

  • 如果redo log写满,那增删改只能等待redo log刷盘,有空余的时候才能继续执行。
  • 避免大事务,否则由于大事务一直未提交,后续所有操作的undo log将一直存在(因为之前这个事务的一致性视图仍然存在),这样undo log占用的表空间就会很大,同时如果大事务是不断更新(比如操作update10万次),后一个事务即使使用select * from t where id = 1也会很慢,因为一致性视图需要不断计算回滚段,而且大事务如果占用了锁,也将导致后续操作被堵塞。(上述分析都是语句RR)

2.索引

索引是B+树,满足最左匹配,同时MySQL5.6针对于支持索引下推(这样覆盖索引就可以过滤掉一部分不满足的数据)。

  • 主键索引存储所有数据
  • 普通索引只存储索引本身和主键
  • 叶子节点从左到右是按照当前索引从小到大排列的
  • 表空洞:删除数据、增加数据且当前数据页空间不足,则页分裂
    • 可以重建表来解决表空洞

总结【完全个人的回忆,验证自己掌握的知识网络】

下方图很重要,但是部分内容在我本机安装的MySQL8.0.29版本已经被解决(比如一个bug)等。

总结下整体对于本文的理解吧。

  • Mysql整体架构分为Server层与引擎层。Server层中包含:

    连接器、【建立连接,过程比较复杂,会验证权限,耗费CPU,因此一般建议长连接,而且权限是在连接建立的时候一次性给的,所以连接不断开,修改的权限无效。默认8h不使用,会自动断开连接,再次查询会报loss connect during query类似的错误】

    分析器、【分析语句,是查询更新还是删除或者改表】

    优化器、【选择索引(函数、类型转化、字符转换、id+1=100等都无法使用索引,要注意)】

    执行器【真正调用执行引擎操作中】

  • DML加MDL读锁、DDL加MDL写锁,读锁之间不冲突,读写或写写之间冲突。

  • OnlineDDL是Mysql5.6之后支持。原理就是DDL先申请拿到MDL写锁,然后退化为MDL读锁,创建临时表进行数据的拷贝,期间执行的操作会记录下来,等到整体操作完成后,会再次申请MDL写锁,临时表替换原表,完成OnlineDDL

  • 索引结构是B+树。原因是17亿数据只需要最多3此磁盘搜索就能查到,磁盘访问慢的瓶颈被降到了很低。数据读取到buffer pool中,其是innodb支持的内存保存数据的缓冲池,数据以数据页为最小单位读取进来,同时为了防止冷库的一张大表全表扫描,造成buffer pool命中率下降,buffer pool被划分成young和old区域,默认进来的都放在old区域,1s内如果被再次访问则会移入young区域。

  • buffer pool中有change buffer、数据页【又分成:脏页、已使用的干净页、未使用的干净页】change buffer是用于如果一条更新\插入\删除应该也包含语句,操作的数据不在内存也就先记录在change buffer中,等待系统merge,这样就减少了从磁盘读到内存的动作(唯一索引,由于需要判断唯一性,因此用不到change buffer优化,因此)(任何操作都会记录到redo log,如果redo log写满了,那系统只能等待redo log记录的数据页flush回磁盘)【因此myqsl根据脏页比例和redo log可写入剩余比例制定了数据页回刷到磁盘的速度,一般剩余空间越多,回刷越慢,相反就会快一些】

  • redo log的写入是WAL的。顺序写入,可以想想孔乙己的黑板

  • Mysql的执行引擎有很多,基于内存的Memory、以及Myisam、Innodb等,其中Innodb由于其支持事务,并具备MVCC,以及redo log的两阶段提交配合bin log 具备crash-safe的能力,已经是MySQL默认使用的引擎了。

  • 索引是B+树,主键索引存储所有的数据,其余只存在索引自己和主键。如果需要查询的几个字段很频繁,可以建立覆盖索引,这样就可以避免回表再查一次!

先总结这些,还有些binlog格式为了现在使用row,而不用statement,或者mixed(二者混合),因为row记录更加详细,而statement是unsafe的,比如delete from t limi 1,主备库如果执行时选择索引不同,删除语句也可能不同。

binlog是按照事务提交是一次性写入的,比如T1时刻执行哪些语句,T2时刻执行哪些语句,而不是我们看innodb那样各个事务开启的时间(比较好理解的是,binlog是MySQL server层的,与引擎无关的,历史不支持事务的也是相同记录,这样就比较好理解binlog为什么这个记了)

行了,还有些主备如何确保一致,GTID、不能直接取出需要计算就得需要临时表,排序需要的sort buffer,join需要的join buffer,为了减少回表的MRR等等就先不提了。
还有主从延迟【大事务、备库消费慢(多线程worker已经可以很好解决了)】

感觉做业务最重要的就是对索引结构,innodb内部查询流程的理解,并且对于锁的理解是特别重要的,最下面的2个原则,2个优化,1个bug牢记!
还有大事务会造成主从延迟,且开启事务时刻的所有事务undo log都得存下来(因为这个大事务事务id比较小,一直没提交,MySQL认为它可能会用),同时如果大事务占用锁,将会影响该表的并发度。大事务一定要避免。
select for update、update、delete都满足下方的2个原则,2个优化,1个bug牢记。牢记!

坚持,永远不要自我怀疑!
学习后有很大的收货
加油,下一篇,Redis走起~。

>>其他记录

你可以在information_schema库的innodb_trx这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s的事务。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

posted @ 2022-05-26 17:03  程序杰杰  阅读(423)  评论(0编辑  收藏  举报