Blog

patience is the key in life


undo log

定义

记录事务执行操作前的数据,用于事务的回滚操作,确保了事务的原子性。同时也应用于MVCC中定位查询语句可见的记录

运用

  1. insert语句 :undo log就记录下insert插入记录的主键id,这样回滚时通过id可以将这条记录删除
  2. update语句:记录下update所操作的记录的字段的旧值,回滚时,恢复旧值即可
  3. delete语句:记录下delete操作的记录,回滚时,insert该条记录

注意点

每一条undo log记录会先保存至buffer pool中的undo log页面,时机合适(间隔一段时间)将undo log页面刷回磁盘

redo log

定义

因为事务提交后,修改的数据是保存在buffer pool中的数据页当中,也就是脏页,但因为IO耗时的原因,脏页并不会马上刷盘。因此,在这期间,如果数据据崩溃,就会造成提交的事务中对数据的修改的丢失。所以,引入了redo log,将每一次提交的事务对数据的修改保存在redo log中,redo log会保存至redo log buffer当中,根据一定的规则将redo log以顺序写的形式写回磁,确保了事务提交后的持久性

注意点

磁盘中存放redo log的文件有大小限制,当文件满时,就需要对没用的数据进行覆盖。而数据是否有用则取决于对应的数据页(脏页)是否落盘,对那些已经落盘的数据可以清理,避免文件不够用

bin log

定义

bin log存储了所有数据表结构变更和数据表数据修改的操作,主要用于主从复制和备份恢复

注意点

bin log采取的是追加写的备份形式,一个bin log文件写满了,就再新建一个,也正因此,bin log保存了数据库中所有数据变更的内容,也因此可以用于主从复制的全量复制以及备份恢复


定义

当一条查询语句的执行时间超出了设定的查询时间,就发生了慢查询

排查与解决办法

排查

   可以通过查询慢查询日志得知是否发生了慢查询

解决

  1. 优化查询语句
     1. 减少查询不必要的列(尽量避免使用select *)
     2. 避免联表查询
  2. 优化索引
     1. 前缀索引优化
     2. 覆盖索引优化
     3. 避免索引失效


定义

两个或两个以上的事务存在一个互相持有对方想要获得的锁且同时又请求获得对方持有的锁的循环链

产生的必要条件

互斥、不可剥夺、请求和保持、循环等待

解决办法

  1. 为每个事务设置一个定时器,超时则回滚该事务,释放拥有的锁资源
  2. 监测死锁,释放死锁关系中某一个事务所拥有的锁资源


行锁

对行记录上锁,但本质上是对行记录的索引上锁

记录锁

对一条记录上锁,被上锁的记录不能被删除、修改

间隙锁

对一个范围内的记录上锁,范围内的数据不能被删除、修改;增加新的数据到范围内

next-key lock

记录锁+间隙锁,左开右闭

  • 一般的select语句并不会对记录上锁,因为innodb默认的隔离级别是可重复读,采用快照读的形式,通过MVCC做事务的隔离。
  • 只有当使用select … for update语句的时候,采取的是当前读的形式,会对范围内的数据加next-key lock。但在一些特殊情况下,next-key lock会退化成间隙锁或记录锁


照着代码自己敲了一遍,能理解的不多,疏通了一下RPC的宏观过程

一个RPC的实现需要三个主体:服务提供者、服务调用者、注册中心

  1. 服务调用者发送HTTP请求给服务提供者
    1. 首先需要将封装好的HTTP请求对象序列化
    2. 将序列化的对象发送出去
  2. 服务提供者对HTTP请求做处理,将处理结果发送HTTP响应给服务调用者
    1. 对收到的序列化字节数组进行反序列化
    2. 对反序列化后的HTTP请求进行处理(根据接收到的参数通过本地注册服务器将获取对应的服务类,并通过反射调用请求方法)
    3. 将处理结果封装成响应对象
    4. 对响应对象进行序列化
    5. 将序列化后的字节数组发送给服务请求者
  3. 服务请求者提取响应对象中的数据
    1. 将收到的序列化字节数组进行反序列化
    2. 根据业务逻辑对响应对象中的数据进行相关处理

服务调用者怎么知道服务提供者的ip地址和端口呢?
这就是注册中心该干的事了

如果有多个服务提供者,那服务调用者应该向哪一个提供者发送请求呢?
这就是负载均衡机制的事了


四大特性

  1. 原子性 (由回滚机制保证)
  2. 隔离性 (由事务的隔离级别保证)
  3. 持久性 (由日志保证)
  4. 一致性 (由前三者共同保证)

隔离级别

隔离脏读、不可重复读以及幻读三种可能出现的问题

读未提交

什么都避免不了

读提交

可以避免脏读

可重复读

可以避免脏读、不可重复读以及很大程度上避免幻读

串行化

全可以避免

MVCC(多版本并发控制)

在读提交和可重复读隔离级别下,都采用了多版本并发控制的方式来实现事务之间的隔离,MVCC是通过Read View来实现的

Read View中存储了当前活跃(创建了的但还未提交)事务的id列表活跃事务中最小的id活跃事务中最大的id+1(下一个新建的事务id)当前事务id

每一条数据记录中还有两列隐藏列,分别是最近一次修改该条记录的事务id以及undo指针

读提交:

在每一次查询前都创建一个Read View,如果所查询的这条记录中最近一次修改的事务id值小于Read View中活跃事务id列表中最小的id值,说明查询到的这条数据是已经在之前提交过的了,因此可以读取。反之,则要通过undo指针寻找到之前的记录,直到该条记录的最近一次修改的事务id值小于活跃事务id列表中最小的id值

可重复读

只在事务开始阶段创建一个Read View,期间不管发生多少次查询,都使用的是一开始创建的这个Read View。其余规则同读提交一样。


count(参数)用来统计符合查询条件的记录中参数值不为null的条数

性能排序:
count()= count(1)> count(主键)> count(普通字段)
count(
)实际上优化器会将其转换成count(0),在查询效率上等同于count(1),因为二者都是恒为非null的,因此,只要判断查询出来的记录条数即是最终查询结果
count(主键)在将符合条件的记录通过走索引表查询出来后还要判断记录的主键值是否为空。
count(普通字段)由于没有建立索引,所以需要走全表扫描,查询效率最差。


为什么Innodb存储引擎使用B+树作为存储索引的数据结构

  1. 查询效率高

因为B+树的非叶子节点只存储索引值而不存储数据值,所以每一个节点能够存储更多的值,进而整个树就呈现一种“矮胖”的感觉。而树的查询效率又跟树高呈正相关,树高越小,查询效率越高。所以B+树的查询效率高。

  1. 支持范围查询

B+树的叶子节点存储所有索引对应的value的数据,并以链表(单向/双向)的形式串联起来,


索引分类

按个数

单列索引、联合索引

按物理存储

主键索引、二级索引

按数据结构

B+树索引、B树索引

索引失效

  1. 对索引字段使用函数、表达式计算;发生隐式类型转换
  2. 左模糊、左右模糊匹配
  3. 未遵循最左匹配原则(针对聚簇索引)

索引优化

  1. 避免索引失效
  2. 避免回表,如果可以,覆盖索引


Redis确保在事务内的命令是顺序一次性不被中断地执行的

Redis以multi()开始一个事务,以execute()执行一个事务

Redis是单线程执行任务的,因此,当它开始执行一个事务时,就会一直到该事务结束才会去处理其他请求,期间不会被其他线程干扰

Redis事务内部不支持回滚,确保了内部简单、轻便

0%