1、索引有哪些。聚簇索引和非聚簇索引区别
2、为什么使用b+树
3、索引失效的场景
4、事务是怎么实现的。mvcc?没有binlog还能实现事务吗
5、一条sql的执行过程。
1、索引有哪些。聚簇索引和非聚簇索引区别
索引有哪些?
b+树索引
大多数MySQL存储引擎的默认索引
哈希索引
innodb存储引擎有个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在b+树索引之上再创建一个哈希索引
全文索引
全文索引一般使用倒排索引实现,记录者关键字到其所在文档的映射。
聚簇索引和非聚簇索引
聚簇索引,表数据是和主键一起存储的,主键索引的叶结点存储行数据(包含了主键值),二级索引的叶结点存储行的主键值。使用的是B+树作为索引的存储结构,非叶子节点都是索引关键字,但非叶子节点中的关键字中不存储对应记录的具体内容或内容地址。
非聚簇索引表
表数据和索引是分成两部分存储的,主键索引和二级索引存储上没有任何区别。使用的是B+树作为索引的存储结构,所有的节点都是索引,叶子节点存储的是索引+索引对应的记录的数据
2、为什么使用b+树
为了减少磁盘读取次数,决定了树的高度不能高。所以选择b树
以页为单位读取使得一次IO就能完全载入一个节点,且相邻的节点能够被预先载入,所以数据放在叶子结点,本质上是一个page页
为了支持查询范围以及关联关系,页中数据需要有序。
b+树是基于b树和叶子节点顺序访问指针进行实现的。具有b树的平衡性,并且通过顺序访问指针来提高区间查询的性能。
3、索引失效的场景
常见的一些场景回答一下。
4、事务是怎么实现的。mvcc?没有binlog还能实现事务吗
脏读:当一个事物正在访问数据并对数据进行了修改,但没提交时,另一个事务访问了这个数据,这个数据是还没提交的数据,则适合读到的数据就是脏数据。
不可重复读:一个数据内多次读同一个数据,这个事务没结束时,另一个事务访问改数据,那可能第一个事务两次读取的结果不同。
幻读,一个事务读取几行数据,另一个事务插入了一些数据时,第一个事务就会发现多了几行数据。
不可重复读重在修改,幻读重在新增、删除。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | √ | √ | √ |
读已提交 | × | √ | √ |
可重复读(mysql的默认级别) | x | x | √ |
串行化 | x | x | x |
事务的基本特性:ACID。
原子性:一个事务中的操作要么全部成功,要么全部失败。
由undo log日志保证,记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
一致性:数据库总是从一个一致性的状态转换到另一个一致性的状态。
一般由代码层面来保证
隔离性:一个事务的修改在最终提交前,对其他事务是不可见的。
由mvcc保证
持久型:一旦事务提交,所做的修改就会永远保存到数据库中。
由内存+redo log保证,mysql修改数据同时在内存和redo log记录这次操作,事务提交的时候通过redo log栓盘,宕机的时候可以从redo log恢复
InnoDB通过 Force Log at Commit
机制保证持久性:当事务提交(COMMIT)时,必须先将该事务的所有日志缓冲写入到重做日志文件进行持久化,才能 COMMIT 成功。
为了确保每次日志都写入 redo log 文件,在每次将 redo log buffer cache 写入重做日志文件后,InnoDB 引擎都需要调用一次 fsync 操作。因此磁盘的性能决定了事务提交的性能,也就是数据库的性能。
redo log拥有两阶段提交。
MVCC
一般来说 MVCC 只在 Read Committed 和 Repeatable Read 两个隔离级别下工作。Read Uncommitted 总是能读取到未提交的记录,不需要版本控制;Serializable 对所有的读取都对加锁,单独靠 MVCC 无法完成。
MVCC 的实现,是通过保存数据在某一个时间点的快照来实现的。因此每一个事务无论执行多长时间看到的数据,都是一样的。所以 MVCC 实现可重复读。
在innodb引擎中就是指在已提交读(READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别下的事务对于SELECT操作会访问版本链中的记录的过程。
MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突
,它的实现原理主要是依赖记录中的 3个隐式字段
,undo日志
, Read View
来实现的。
三个隐式字段是:最近修改的事务id,回滚指针,还有隐式的自增id。
undo log 主要分为两种insert undo log和update undo log
已提交读和可重复读的区别就在于它们生成ReadView的策略不同。
ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是begin了还未提交的事务。通过这个列表来判断记录的某个版本是否对当前事务可见。
已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。
这就是Mysql的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的隔离级别。
bin log作用
复制和恢复数据
MySQL在公司使用的时候往往都是一主多从结构的,从服务器需要与主服务器的数据保持一致,这就是通过binlog来实现的
数据库的数据被干掉了,我们可以通过binlog来对数据进行恢复。
5、一条sql的执行过程。
更新一条数据到事务的提交过程:
首先执行器根据 MySQL 的执行计划来查询数据,先是从缓存池中查询数据,如果没有就会去数据库中查询,如果查询到了就将其放到缓存池中在数据被缓存到缓存池的同时,会写入 undo log 日志文件更新的动作是在 BufferPool 中完成的,同时会将更新后的数据添加到 redo log buffer 中完成以后就可以提交事务,
在提交的同时会做以下三件事
1、将redo log buffer中的数据刷入到 redo log 文件中
2、将本次操作记录写入到 bin log文件中
3、将 bin log 文件名字和更新内容在 bin log 中的位置记录到redo log中,同时在 redo log 最后添加 commit 标记