走进mysql基础
前言
作为后端猿的我们,不出意外每天都会和mysql打交道。除了每天写不腻的CURD语句,关于mysql我们应该要了解它的那些基础知识呢?
直入主题
简单画出mysql的逻辑架构图?
接 入 层 |
mysql常见的引擎有哪些,区别是什么?
- InnoDB
- 支持事务
- 行锁
- 聚簇索引
- 引申问题:什么是聚簇索引?索引存放实际数据
- 辅助索引(二级索引)索引存放的是主键
- MyISAM
- 不支持事务
- 表锁
- 崩溃无法安全恢复
- 非聚簇索引
- 引申问题:什么是非聚簇索引?索引存放实际数据的地址
- 辅助索引(二级索引)索引存放的还是实际数据的地址
- Memory
- 基于内存
- 表锁
- 字段长度固定,不支持blob,text, 即使指定vachar实际储存也会转为char
- Archive
- 只支持insert/select操作
- 适合日志等
- …
什么是事务的ACDI概念?
- A: Atomicity, 原子性, 一个事务的所有操作视为一个整体,要不全部成功,要不全部失败。
- C: Consistency, 一致性, 一个事务下的所有的数据状态变更,只有事务提交成功才全部变更。
- D: Durability, 持久性, 一旦事务提交成功,产生的数据变更将永久保存在数据库中。
- I: Isolation, 隔离性, 一个事务在提交之前对其他事务不可见。
什么是脏读,幻读,不可重复读?
- 脏读:读取未提交事务的数据,数据可能被回滚,不符合隔离性的定义。
- 幻读:一个事务批量读取了一批数据时,另一个事务提交了新的数据,当之前的事务再次读取时,会产生幻影行。
- 不可重复读:执行两次相同的查询,可能得到不同的结果。
mysql事务的隔离级别有哪些?默认的隔离级别是什么?
- 未提交读:一个事务还未提交,另一个事务就可以读取,这样导致的后果,脏读。
- 提交读(又叫,不可重复读):一个事务未提交对其他事务不可见,但是会产生幻读和不可重复读。
- 可重复读(mysql默认隔离级别):保证同一个事务下多次读取的结果一致,但是会产生幻读。
- 可串行化:严格的串行阻塞,并发能力不好。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read Uncommitted | √ | √ | √ |
Read Committed | × | √ | √ |
Repeatable Read | × | × | √ |
Serializable | × | × | × |
什么是MVCC?简述MVCC的作用及原理?
MVCC:Multi Version Concurrency Control, 多版本并发控制,mysql防止幻读的一种技术手段。每行数据存在间隙行,间隙行存放该行数据的创建时间,删除时间,这里的时间实际是事务的版本号。当,
- select数据时:只查询创建时间小于等于当前事务版本号 -> 当前事务或当前事务之前插入的行,删除时间大于当前版本号的行 -> 当前事务版本前未被删除的行。
- update数据时:在原有行a的基础上复制行a’,行a的删除时间设置为当前的事务版本号,行a’的创建时间设置为当前的事务版本号。
- insert数据时:记录创建时间为当前事务版本号。
- delete数据时:记录删除时间为当前事务版本号。
死锁是怎么出现的,并写出简单示例?
死锁产生的原因是两个事务互相等待对方释放,产生了循环依赖,mysql采用了死锁检测(检测到循环依赖返回错误)和死锁超时(超时回滚持有行锁最少的事务)的方式尽可能去避免死锁。例如:
行锁: |
什么是聚簇索引和非聚簇索引?
- 聚簇索引:InnoDB, B+树的叶子节点存放实际数据。
- 非聚簇索引:MyISAM, B+树的叶子节点存放实际数据的地址。
什么是覆盖索引?
覆盖索引:要查询的行被索引覆盖,从索引中可以直接读取,不需要回表查询。例如:
CREATE TABLE `demo_table`( |
explain select `username` from `demo_table` where `username` = 'demo'; |
Extra里的Using index就是使用了覆盖索引的意思。
什么是索引的最左前缀匹配原则?
个人目前理解:例如使用联合索引,从左向右依次匹配,未匹配到索引字段或第一个范围查找(between、like、大于、小于)为止,及该部分索引有效。
InnoDB为什么不采用红黑树而采用B+树作为索引存放数据结构,并简要画出B+树?(目前我个人的理解比较浅欢迎积极纠正~)
红黑树本质是二叉树,每个节点最多拥有两个子节点,所以红黑树的深度较深,而B树每个节点最多可以有n个子节点,假如每个节点拥有100个子节点,那百万级的数据我们基本上只需要深度是3就可以存下 => 100^3,这样就减少的io次数(一个节点的大小通常为磁盘一个页的大小)。又有“局部性原理”(一旦一个数据被查询,那么它附近的数据可能也会需要被查询),其次B+树的叶子节点构成一个链表,这样我们就可以很容易的查询出一段范围的数据,其次B+树的根节点和内部节点只存放该索引下一个子节点的位置的指针,数据只存放在叶子节点里,这样非叶子节点就可以有更多的空间存放索引的位置,索引的范围就可以尽可能的大,从而树的深度就可能的小。
结语
后续持续修正和补充,如果有什么写的不对的地方欢迎大家积极指正,谢谢大家。