MySql 三大知识点——索引、锁、事务,详解

做者:莫那鲁道java

来源:http://thinkinjava.cn/2019/03/16/2019-03-16-mysqlmysql

1.索引面试

索引,相似书籍的目录,能够根据目录的某个页码当即找到对应的内容。算法

索引的优势:1. 天生排序,2. 快速查找。sql

索引的缺点:1. 占用空间,2. 下降更新表的速度。数据库

注意点:小表使用全表扫描更快,中大表才使用索引。超级大表索引基本无效。并发

索引从实现上说,分红 2 种:汇集索引和辅助索引(也叫二级索引或者非汇集索引)异步

从功能上说,分为 6 种:普通索引,惟一索引,主键索引,复合索引,外键索引,全文索引。分布式

详细说说 6 种索引:性能

一、普通索引:最基本的索引,没有任何约束。 二、惟一索引:与普通索引相似,但具备惟一性约束。 三、主键索引:特殊的惟一索引,不容许有空值。 四、复合索引:将多个列组合在一块儿建立索引,能够覆盖多个列。 五、外键索引:只有InnoDB类型的表才可使用外键索引,保证数据的一致性、完整性和实现级联操做。 六、全文索引:MySQL 自带的全文索引只能用于 InnoDB、MyISAM ,而且只能对英文进行全文检索,通常使用全文索引引擎(ES,Solr)。

注意:主键就是惟一索引,可是惟一索引不必定是主键,惟一索引能够为空,可是空值只能有一个,主键不能为空。

另外,InnoDB 经过主键聚簇数据,若是没有定义主键且没有定义汇集索引, MySql 会选择一个惟一的非空索引代替,若是没有这样的索引,会隐式定义个 6 字节的主键做为聚簇索引,用户不能查看或访问。

简单点说:

一、设置主键时,会自动生成一个惟一索引,若是以前没有汇集索引,那么主键就是汇集索引。 二、没有设置主键时,会选择一个不为空的惟一索引做为汇集索引,若是尚未,那就生成一个隐式的 6 字节的索引。

MySql 将数据按照页来存储,默认一页为 16kb,当你在查询时,不会只加载某一条数据,而是将这个数据所在的页都加载到 pageCache 中,这个其实和 OS 的就近访问原理相似。

MySql 的索引使用 B+ 树结构。在说 B+ 树以前,先说说 B 树,B 树是一个多路平衡查找树,相较于普通的二叉树,不会发生极度不平衡的情况,同时也是多路的。

B 树的特色是:他会将数据也保存在非页子节点。

看图可知:

而这个特色会致使非页子节点不能存储大量的索引。

而 B+ Tree 就是针对这个对 B tree 作了优化。以下图所示:

咱们看到,B+ Tree 将全部的 data 数据都保存到了叶子节点中,非也子节点只保存索引和指针。

咱们假设一个非页子节点是 16kb,每一个索引,即主键是 bigint,即 8b,指针为 8b。那么每页能存储大约 1000 个索引(16kb/ 8b + 8b).

而一颗 3 层的 B+树可以存储多少索引呢?

以下图:

大约可以存储 10 亿个索引。一般 B+ 树的高度在 2-4 层,因为 MySql 在运行时,根节点是常驻内存的,所以每次查找只须要大约 2 -3 次 IO。能够说,B+ 树的设计,就是根据机械磁盘的特性来进行设计的。

知道了索引的设计,咱们可以知道另一些信息:

一、MySql 的主键不能太大,若是使用 UUID 这种,将会浪费 B+ 树的非叶子节点。 二、MySql 的主键最好是自增的,若是使用 UUID 这种,每次插入都会调整 B+树,从而致使页分裂,严重影响性能。

那么,若是项目中使用了分库分表,咱们一般都会须要一个主键进行 sharding,那怎么办呢?在实现上,咱们能够保留自增主键,而逻辑主键用来做为惟一索引便可。

2.锁机制

关于 Mysql 的锁,各类概念就会喷涌而出,事实上,锁有好几种维度,咱们来解释一下。

1.类型维度

共享锁(读锁 / S 锁) 排它锁(写锁 / X 锁)

类型细分:

  • 意向共享锁

  • 意向排他(互斥)锁

悲观锁(使用锁,即 for update)

乐观锁(使用版本号字段,相似 CAS 机制,即用户本身控制。缺点:并发很高的时候,多了不少无用的重试)

2.锁的粒度(粒度维度)

表锁 页锁(Mysql BerkeleyDB 引擎) 行锁(InnoDB)

3.锁的算法(算法维度)

Record Lock(单行记录) Gap Lock(间隙锁,锁定一个范围,但不包含锁定记录) Next-Key Lock(Record Lock + Gap Lock,锁定一个范围,而且锁定记录自己, MySql 防止幻读,就是使用此锁实现)

4.默认的读操做,上锁吗?

默认是 MVCC 机制(“一致性非锁定读”)保证 RR 级别的隔离正确性,是不上锁的。

能够选择手动上锁:select xxxx for update (排他锁); 

select xxxx lock in share mode(共享锁),称之为“一致性锁定读”。

使用锁以后,就能在 RR 级别下,避免幻读。固然,默认的 MVCC 读,也能避免幻读。

既然 RR 可以防止幻读,那么,SERIALIZABLE 有啥用呢?

防止丢失更新。例以下图:

这个时候,咱们必须使用 SERIALIZABLE 级别进行串行读取。

最后,行锁的实现原理就是锁住汇集索引,若是你查询的时候,没有正确地击中索引,MySql 优化器将会抛弃行锁,使用表锁。

3.事务

事务是数据库永恒不变的话题, ACID:原子性,一致性,隔离性,持久性

四个特性,最重要的就是一致性。而一致性由原子性,隔离性,持久性来保证。

原子性由 Undo log 保证。Undo Log 会保存每次变动以前的记录,从而在发生错误时进行回滚。隔离性由 MVCC 和 Lock 保证。这个后面说。持久性由 Redo Log 保证。每次真正修改数据以前,都会将记录写到 Redo Log 中,只有 Redo Log 写入成功,才会真正的写入到 B+ 树中,若是提交以前断电,就能够经过 Redo Log 恢复记录。

而后再说隔离性。

隔离级别:

一、未提交读(RU)

二、已提交读(RC)

三、可重复读(RR)

四、串行化(serializable)

每一个级别都会解决不一样的问题,一般是3 个问题:脏读,不可重复读,幻读。一张经典的图:

这里有个注意点,关于幻读,在数据库规范里,RR 级别会致使幻读,可是,因为 Mysql 的优化,MySql 的 RR 级别不会致使幻读:在使用默认的 select 时,MySql 使用 MVCC 机制保证不会幻读;

你也可使用锁,在使用锁时,例如 for update(X 锁),lock in share mode(S 锁),MySql 会使用 Next-Key Lock 来保证不会发生幻读。前者称为快照读,后者称为当前读。

原理剖析:

一、RU 发生脏读的缘由:RU 原理是对每一个更新语句的行记录进行加锁,而不是对整个事务进行加锁,因此会发生脏读。而 RC 和 RR 会对整个事务加锁。 二、RC 不能重复读的缘由:RC 每次执行 SQL 语句都会生成一个新的 Read View,每次读到的都是不一样的。而 RR 的事务从始至终都是使用同一个 Read View。 三、RR 不会发生幻读的缘由: 上面说过了。

那 RR 和 Serializble 有什么区别呢?答:丢失更新。本文关于锁的部分已经提到。

MVCC 介绍:全称多版本并发控制。

innoDB 每一个汇集索引都有 4 个隐藏字段,分别是主键(RowID),最近更改的事务 ID(MVCC 核心),Undo Log 的指针(隔离核心),索引删除标记(当删除时,不会当即删除,而是打标记,而后异步删除);

本质上,MVCC 就是用 Undo Log 链表实现。

MVCC 的实现方式:事务以排它锁的方式修改原始数据,把修改前的数据存放于 Undo Log,经过回滚指针与数据关联,若是修改为功,什么都不作,若是修改失败,则恢复 Undo Log 中的数据。

多说一句,一般咱们认为 MVCC 是相似乐观锁的方式,即便用版本号,而实际上,innoDB 不是这么实现的。固然,这不影响咱们使用 MySql。

更多技术干货

 

近期100多篇技术干货,升职加薪必看

百度、腾讯、阿里、谷歌 面试题视频详解合集

深刻 Redis 主从复制的原理详解

ZooKeeper 一致性协议 ZAB 原理

Google 出品的 Java 编码规范,权威又科学

46张PPT讲述JVM、GC算法和性能调优

基于 Zookeeper 的分布式锁实现

30 道 Dubbo 面试题及答案

RDB 和 AOF 持久化的原理是什么?

相关文章
相关标签/搜索