mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)

一、内部结构:

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第1张图片
mysql是一个可拔插的内部结构,包括连接池、解析器、查询优化器、缓存区(cache和buffer)、file system(redo、undo、binlog、索引等)、存储引擎。
常用的知识点:

  • WAL: 写前日志包括redo和undo
  • redo log : 记录事务的动作
  • undo log: 记录事务的操作
  • bin log: 主从数据库中记录主的日志
  • relay log : 主从数据库中从数据库的日志
  • 存储引擎:innodb myisam dbd memory

问题1 : select语句的执行过程:

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第2张图片

问题2:INNODB和MYISAM的比较:

  • INNODB有事务、支持外键、支持聚集索引、支持行锁、适用于安全性较高、且写操作较多的表(订单表、账号表)
  • MYISAM无事务、无外键、支持非聚集索引、支持标所、查询所读快、支持批量插入、适用于读操作较多、或需要大规模插入的表(论坛表、回复表)

二、事务:

问题1 : 什么是事务、有哪些特性?

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第3张图片

  • 事务就是一组对数据操作的集合
  • A 原子性:事务要么都做、要么都不做
  • C 一致性:事务不影响数据库完整性(约束完整性、数据完整性)
  • I 隔离性:两个事务之前互相不影响(锁+MVCC)
  • D 持久性:事务修改后,进行持久化保存

其中原子性、持久性、隔离性中的MVCC由redo和undo来实现。而一致性中的数据完整性是由其他三个特征共同作用的结果,并不是依赖于某一种单独的技术。

原理:在操作事务前,先要在磁盘中写数据到buffer pool中,当此时出现断网等意外操作时,会先去redo log中寻找事务做了哪些操作,再去undo log中找到事务到底改变了什么数据,这样整个事务就完成了恢复。

问题2 : 事务的隔离级别于数据库隔离出现问题的对应关系是什么?

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第4张图片
脏读:RU下,事务A读到了事务B未提交的数据。

不可重复度:RC下,事务A前后两次读到了同一字段不同值(UPDATE操作,值改变)事务B修改了字段值。
幻读:RR下,事务A读到前后两次读到了不同数量的同一字段(INSERT操作,数量改变)事务B插入了数据

问题3 : MVCC实现原理

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第5张图片
mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第6张图片
事务1在修改数据前:

  • 排它锁锁定事务1、记录操作到redo log
  • 讲原修改行复制到 undo log 中 , 记录数据
  • 增加事务号、讲回滚指针连接
  • purge 线程用来扫描这次事务最早的操作,将之前的日志进行删除以保证redo log 不会无限写入

MVCC优点:读不加锁、读写分离

问题4 : 事务的开启方式:

第一种:直接开启事务

START TRANSACTION;
		事务代码
		commit;

第二中:关闭自动提交

set autocommit=0
		事务代码
		commit

三、索引及优化:

问题1 : mysql有什么索引:

以内部结构来分类

  • 哈希索引:通过哈希函数计算哈希值,对应某个地址,查询速度快。但无法范围查询,切会出现哈希碰撞(解决方式为碰撞位置组成单链表)
  • B+树索引:mysql的主流索引。

以索引类型来划分

  • 聚集索引: innodb的索引类型,B+树的叶子节点里存的是索引和数据。对应着Innodb的表,只有表文件和索引数据文件两个。
  • 非聚集索引:myisam的索引类型,B+树的叶子节点里存的是数据文件所在的地址。对应着myisam的表,存在表文件、索引文件、数据文件三个文件。

以功能类型来划分
主键索引、单值索引、唯一索引、联合索引、覆盖索引

问题2 :为什么选用B+树作为索引:

二叉搜索树:

  • 左子树key<根节点key<右子树的key

  • 所有树都是二叉树

  • 该类型极端的时候,会变成链表、导致效率降低。
    AVL完全平衡二叉树:

  • 左右子树的高度差不大于1

  • 插入节点改变了高度后通过自旋(左旋、右旋、左右旋、右左旋)操作实现高度特性

  • 插入操作过多会导致性能下降

  • 适用于查找较多的场景 如windows底层
    红黑树:
    mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第7张图片

  • 根结点为黑

  • 每个红色节点有两个黑色节点

  • 叶子结点是黑色节点

  • 任一结点到每一个叶子结点的所有路径都有相同个数的黑色结点

  • 从根结点到叶子结点的最长路径 <= 两倍的最短路径

  • 解决了AVL的问题,插入操作在最坏情况下也是高效的

  • 可以被使用到操作插入、删除较多的场景(linux 进度调动、java和哈希map)

到这里已经是mysql索引底层的基本结构了,但是由于mysql的工作性质需要进行大量的I/O磁盘读写操作,为了降低刷盘的次数、我们将红黑树进行放矮、放宽、并将每个节点存储多个值、就出现了B+树:
mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第8张图片
B+树:将整个树进行放矮、放宽后,对于刷盘的次数就降低到了个位数。B+树被广泛用于mysql的索引。

在线数据结构模拟网站

问题3 :如何使用索引:

# 创建索引
Create Index index_name on Table(name, age)

# 更改索引
Alter Table ADD index index_name on Table(name, age)

# 删除索引
Drop index index_name on Table

# 查看索引
Show index From table_name

问题4 :索引的使用场景:

适合创建索引条件

  • 主键自动建立唯一索引
  • 频繁作为查询条件的字段应该建立索引
  • 查询中与其他表关联的字段,外键关系建立索引
  • 单键/组合索引的选择问题,组合索引性价比更高
  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序效率(order by 要注意覆盖索引顺序和使用顺序相同)
  • 查询中统计或者分组字段(group by 实质是先排序再分组,也需要保持索引字段使用和覆盖索引顺序的一致性)

不适合创建索引条件

  • 表记录少的
  • 经常增删改的表或者字段
  • where条件里用不到的字段不创建索引
  • 过滤性不好的不适合建索引(查询结果范围太大)

问题5 :7种join连接

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第9张图片

# 由于mysql没有外连接,因此使用union进行相加得到外连接
# 此处为全部A+B
select * from A left join B on A.id = B.id where B.id = NULL 
union 
select * from a left join B on A.id = B.id where A.id = NULL

# A+B 减去公共部分
select * from A left join B on A.id = B.id where B.id = NULL 
union 
select * from a left join B on A.id = B.id where A.id = NULL

问题6 :如何分析sql的性能(执行顺序、索引使用性能)

explain select * from A

在这里插入图片描述

id:执行顺序

  • id相同时,执行顺序由上至下
  • id不同时,执行顺序由大到小
  • id又相同又不同,先大小再上下

type:访问类型
性能排行:system>const>eq_ref>ref>range>index>all

  • system:系统表
  • const:常量
  • eq_ref: 唯一索引或主键索引,返回为一行数据
  • ref: 非唯一索引,返回为多行数据
  • range: 给定范围内检索,使用一个索引来选择行数据
  • index: 全索引检索
  • all: 全表检索
    正常情况,优化到ref/eq_ref

possible_keys

  • 推测可能使用的索引字段

keys

  • 实际使用的索引字段

key_len

  • 使用索引检索用到了多少行数据,同结果下越少越好

extra

  • using filesort: 见于order by的索引失效,需要优化
  • using temporary:见于 group by的索引失效,需要优化
  • using index :使用索引,不需要优化

四、查询优化:

问题1 :数据库性能下降的原因由哪些?

  • select 语句写的烂
  • 索引失效
  • 关联查询太多(设计缺陷)
  • 服务器调优以及各个参数设置问题(缓冲、线程数等)
  • 未使用读写分离(主从架构模式)

问题2 :如何避免索引失效:

全值匹配我最爱,最左前缀要遵循
带头大哥不能死,中间兄弟不能断
索引列上少计算,范围之后全失效
like百分写最右,覆盖索引不写星
不等控制还有or,用了索引就失效

  • 最左前缀原则的特殊情况包含全部正确的 反序列(如原ABC 使用为CBA)
  • like 的百分号放到左侧,相当于可以排序出前面开头的部分,这种情况并不失效
  • group by 和 order by 也遵守上述原则

问题3 :查询优化思路:

** 永远用小表驱动大表**

# 当表A的数据量   >    表B       使用in
select * from A in (select id from B )

# 当表A的数据量   <    表B       使用exist
select * from A exist (select id/'a'/1 from B where B.id = A.id )

# exist 的原理是,难道某一行数据,去A表查看是否存在
# 后面的select 其实查的是一条记录,因此 id/'A'/1 相同

** group by 和 sort by尽量使用索引进行排序 **

  • mysql的排序方式分为:indexsort 和 filesort

  • filesort分为单路查询和双路查询

  • 单路查询:在buffer中处理数据,只访问一次I/O磁盘(当buffer中数据过多时,会分多次处理数量,导致多次访问磁盘)

  • 双路查询:访问两个I/O磁盘

当group by 或 sort by 没有遵循最左原则时,会导致文件内排序中的多路查询(双路或单路失效变成多路)

解决方案:

  • 使用索引方式(indexsort)进行排序,不让索引失效
  • select * 语句用select id, age 的形式,减少进入buffer pool 的字段数量
  • 提高 sort_buffer_size
  • 提高 max_length_for_sort_data

问题4 :如何分析慢sql的具体原因(底层各部分耗时原理):

  • 开启慢sql日志,设置慢sql阈值(如5s以上为慢sql)
  • 抓取所有慢sql进行分析
  • 使用explain + 慢 sql 分析(一般到这里已经解决了)
  • 使用show profile 关键字进行分析(少部分进行底层分析)

五、锁机制:

问题1 :mysql锁机制基础

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第10张图片

问题2 :锁分类

以锁的作用分类:

  • 共享锁 (读锁)
  • 排它锁 (写锁)

以使用方式分类:

  • 乐观锁: 人为实现, 首先增加版本号version = 1 ,当更新数据时对比版本号,相等时更改,不等时返回
  • 悲观锁:现有的共享锁、排他锁都是悲观锁
  • 区别: 乐观锁处理的是程序操作,不影响数据库层面的数据操作,悲观锁影响的是数据库数据的操作。

问题3 :MYISAM表锁实现

# 给 t1 表上写锁
lock table T1 write

# 给 t1 表上读锁
lock table T1 read

# 解锁
unlock table 

  • 读锁会阻塞写,但不会阻塞读
  • 写锁会直接阻塞读写

问题4 :INNDB行锁实现

# 给 T1表 一行上写锁
select * from T1 where id = 1 lock in share mode
# 提交就完成了解锁
commit

# 给 T1表 一行上写锁
select * from T1 where id = 1 for update 
# 解锁
commit 

  • 共享锁会阻塞写操作,不会阻碍读操作,加了共享锁后只能再加共享锁

  • 排它锁会阻塞读写操作,加了排它锁后不能再加锁

问题5 :行锁的缺陷

当无索引进行查询时,行锁会升级为表锁

update table set b = '9002' and a = 1111 for update
# (注意这里a字段是字符型,不加引号使得索引失效,行锁升级为表锁)

间隙锁使用范围条件查询会索镇无数据的行

update table set b = '9002' and a >'0' and a<'100' for update

# 这里的a 会锁住 (0,100)区间内的所有值,即便不存在的值也会被锁住

问题6 :锁的优化建议

  • 让数据通过索引来完成,避免行锁升级为表锁
  • 合理设计索引,减少锁的使用
  • 减少检索条件,避免间隙锁(锁住不存在的行数据)
  • 控制事务大小,减少资源锁定时间和范围
  • 尽可能的降低隔离级别

六、读写分离:

mysql高级(底层存储引擎、事务、索引及优化、查询优化、锁机制、读写分离-主从结构)_第11张图片

  • Master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);
  • Slave将Master的二进制日志事件(binary log events)拷贝到它的中继日志(relay log);
  • I/O thread 和 sql thread 负责slave数据库的I/O读写和sql解析

主从架构具有多种形式:一般使用一主多从(一主四从)
还有双主、环形多主、一主一从(备用主服务器)多从
等多种架构方式,根据具体场景进行得失的考量

你可能感兴趣的:(学习记录)