索引常见的几种类型
索引常见的类型有哈希索引,有序数组索引,二叉树索引,跳表等等。
在建表的时候我们可能会添加多个索引,而InnDB会为每个索引建立一个B+树进行存储索引,假如我们在建表的时候创建了一个主键索引和普通索引,那么这时候InnDB会为我们建立两个B+索引树
一个是主键的 聚簇索引,另一个是普通索引的 辅助索引
辅助索引上面的叶子节点的值只是存了主键的值,而在主键的 聚簇索引 上的叶子节点才是存上了整个值
回表
什么是回表?就是MySQL在辅助索引上找到对应的主键值并通过主键值在聚簇索引上查找所要的数据就叫回表
但在有时候我们查辅助索引的时候就已经满足了我们需要查的数据,这个时候InnDB就会进行一个叫覆盖索引的操作来提升效率,减少回表
简单来说,覆盖索引就是当我们走辅助索引的时候能获取到我们所需要的数据的时候不需要再次进行回表操作的操作。
锁
全局锁
MySQL提供了一个加全局读锁的方法,命令是Flush tables with read lock (FTWRL)。你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
表锁
MDL元数据锁,MDL锁用来保证只有一个线程能对该表进行表结构更改
MDL分为 MDL写锁 和 MDL读锁,加锁规则是这样的
- 当线程对一个表进行 CRUD 操作的时候会加 MDL读锁
- 当线程对一个表进行 表结构更改 操作的时候会加 MDL写锁
- 写锁和读锁,写锁和写锁互斥,读锁之间不互斥
使用MDL的锁的命令是:lock tables *** read/write;
这种锁是一种处理并发的方式,但在InnDB中常用的是行锁
行锁
其实行锁就是两个锁,写锁(排他锁)和读锁(共享锁)
共享锁(S锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。 也叫做读锁:读锁是共享的,多个客户可以同时读取同一个资源,但不允许其他客户修改。
排他锁(X锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁。
但是行锁会引起死锁问题,此处需要注意
next-key锁
MVCC 和行锁是无法解决 幻读 问题的,这个时候 InnoDB 使用了 一个叫 GAP锁(间隙锁) 的东西,它配合 行锁 形成了 next-key锁,解决了幻读的问题。
但是因为它的加锁规则,又导致了扩大了一些加锁范围从而减少数据库并发能力。具体的加锁规则如下:
- 加锁的基本单位是next-key lock 就是行锁和GAP锁结合。
- 查找过程中访问到的对象就会加锁。
- 索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
- 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
- 唯一索引上的范围查询会访问到不满足条件的第一个值为止