前言
作为后端猿的我们,不出意外每天都会和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采用了死锁检测(检测到循环依赖返回错误)和死锁超时(超时回滚持有行锁最少的事务)的方式尽可能去避免死锁。例如:
行锁:
UPDATE `table_demo` SET `a` = 'test' WHERE `b` = 'lalala';
UPDATE `table_demo` SET `b` = 'test' WHERE `a` = 'lalala';
UPDATE `table_demo` SET `b` = 'test' WHERE `a` = 'lalala';
UPDATE `table_demo` SET `a` = 'test' WHERE `b` = 'lalala';
什么是聚簇索引和非聚簇索引?
- 聚簇索引:InnoDB, B+树的叶子节点存放实际数据。
- 非聚簇索引:MyISAM, B+树的叶子节点存放实际数据的地址。
什么是覆盖索引?
覆盖索引:要查询的行被索引覆盖,从索引中可以直接读取,不需要回表查询。例如:
CREATE TABLE `demo_table`(
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`username` char(32) NOT NULL DEFAULT '' COMMENT '用户名',
`password` char(32) NOT NULL DEFAULT '' COMMENT '密码',
PRIMARY KEY (`id`),
KEY `idx_username` (`username`)
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
explain select `username` from `demo_table` where `username` = 'demo';
+----+-------------+------------+------+---------------+--------------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+--------------+---------+-------+------+--------------------------+
| 1 | SIMPLE | demo_table | ref | idx_username | idx_username | 96 | const | 1 | Using where; Using index |
+----+-------------+------------+------+---------------+--------------+---------+-------+------+--------------------------+
Extra里的Using index就是使用了覆盖索引的意思。
什么是索引的最左前缀匹配原则?
个人目前理解:例如使用联合索引,从左向右依次匹配,未匹配到索引字段或第一个范围查找(between、like、大于、小于)为止,及该部分索引有效。
InnoDB为什么不采用红黑树而采用B+树作为索引存放数据结构,并简要画出B+树?(目前我个人的理解比较浅欢迎积极纠正~)
红黑树本质是二叉树,每个节点最多拥有两个子节点,所以红黑树的深度较深。
B树每个节点最多可以有n个子节点,根节点常驻内存且每个节点刚好申请1个页的大小,假如每个节点拥有100个子节点,那百万级的数据我们基本上只需要深度是3就可以存下 => 100^3,这样就减少的io次数(一个节点的大小通常为磁盘一个页的大小)。
又有“局部性原理”(一旦一个数据被查询,那么它附近的数据可能也会需要被查询),其次B+树的叶子节点构成一个链表,这样我们就可以很容易的查询出一段范围的数据,其次B+树的根节点和内部节点只存放该索引下一个子节点的位置的指针,数据只存放在叶子节点里,这样非叶子节点就可以有更多的空间存放索引的位置,索引的范围就可以尽可能的大,从而树的深度就可能的小。
结语
后续持续修正和补充,如果有什么写的不对的地方欢迎大家积极指正,谢谢大家。
扫面下方二维码关注我的技术公众号,及时为大家推送我的原创技术分享