如果你想进入一个大工厂,mysql是不会做到的。快来接受mysql面试的挑战,看看你能坚持到哪里。
Myisam引擎是版本之前的默认引擎,支持全文检索、压缩、空间函数等,但不支持事务和行级锁,因此一般用于查询量大、插入量少的场景。而且,Myisam不支持外键,索引和数据是分开存储的。
Innodb基于聚集索引,与myisam相反,myisam支持事务、外键和通过MVCC的高并发性,在MVCC中索引和数据存储在一起。
根据数据结构,索引主要包括B+树和哈希索引。
假设我们有一个具有以下结构的表:
创建表user(id int(11)不为null,age int(11)不为null,主键(id),键(ag));
B+树是一种左小右大的顺序存储结构。节点只包含id索引列,叶节点包含索引列和数据。这种将数据和索引存储在一起的索引模式称为聚集索引,一个表只能有一个聚集索引。假设没有定义主键,InnoDB将选择一个唯一的非空索引,如果没有,则隐式定义一个主键作为聚集索引。
这是主键聚集索引存储的结构,那么非聚集索引的结构是什么呢?非聚集索引(辅助索引)保存主键id值,而myisam保存数据地址。
最后,让我们看看InnoDB和Myisam中聚集索引和非聚集索引之间的区别
重写索引是指一个查询,如果一个索引包含或重写了所有要查询的字段的值,我们称之为重写索引,不需要查询回表。
要确定查询是否是重写索引,我们只需要解释sql
语句,以查看Extra的结果是否为“使用索引”。
以上面的user表为例,让我们添加一个name字段并尝试一些查询。
解释从用户选择*,其中年龄=1;//查询名称无法从索引数据中获取解释选择id,从用户中获取年龄=1;//可以直接从索引中检索
Mysql锁分为共享锁和独占锁,也称为读锁和写锁。
读锁是共享的,可以通过锁在共享模式实现。这时,你只能读不能写。
写锁是独占的,并阻止其他写锁和读锁。从粒度上区分,可以分为表锁和行锁。
表锁锁定整个表,并阻止其他用户对表的所有读写操作,如alter在修改表的结构时锁定表。
行锁可以分为乐观锁和悲观锁。悲观锁可以通过for update实现,乐观锁可以通过版本号实现。
ACID的基本事务特征是:
原子性意味着事务中的所有操作要么成功,要么失败。
一致性意味着数据库总是从一种一致状态转换到另一种一致状态。比如A给B转账100元,假设中间执行sql时系统崩溃,A不会损失100元,因为事务没有提交,修改也不会保存到数据库。
隔离意味着一个事务的修改对其他事务是不可见的,直到它最终提交。
持久性意味着一旦提交了事务,更改就会永久保存到数据库中。
隔离有四个隔离级别,分别是:
Read uncommit Read是未提交的,可能会从其他事务中读取未提交的数据,也称为脏读。
使用
用户应该已经读取了ID=1的用户年龄,应该是10,结果是其他事务没有提交的已读事务,结果是已读事务年龄=20,这称为脏读。
该read commit read已提交,两次读取的结果不一致,称为不可重复读取。
不可重复读取解决了脏读取的问题,脏读取只读取已提交的事务。
用户启动事务以读取ID=1,用户查询Age=10,并再次读取以查找结果=20。在同一事务中,同一查询读取不同的结果,称为不可重复读取。
可重复读取,这是mysql的默认级别,每次读取都是一样的,但有可能出现幻影读取。
通常不使用的Serializable会锁定每行读取的数据,从而导致大量超时和锁定争用问题。
原子性由undo log日志保证,它记录需要回滚的日志信息。回滚事务时,已成功执行的sql将被撤消
C语言的一致性通常在代码级别得到保证
I隔离由MVCC保证
D持久性由内存+重做日志保证。Mysql修改数据,同时将此操作记录在内存和重做日志中。当事务提交时,可以通过重做日志来刷它,当事务关闭时,可以从重做日志中恢复它
要说幻影阅读,首先要了解MVCC。MVCC被称为多版本并发控制,实际上是保存数据在某个时间节点的快照。
我们实际上每行隐藏两列,即创建时间版本号、过期(删除)时间版本号,并且版本号在每次新事务启动时自动递增。
让我们以上面的用户表为例。假设我们插入两段数据,实际上应该如下所示。
此时,假设小明执行查询,并且current_version=3
选择*
来自id<=3的用户;复制代码
同时,小红此时启动事务修改id=1,current_version=4的记录
更新用户集name='Zhang San San',其中ID=1;复制代码
成功执行后的结果如下
如果Blackie仍在删除ID=2,current_version=5的数据,则执行后的结果如下所示。
由于MVCC的原理是发现创建的版本小于或等于当前事务版本,删除的版本为空或大于当前事务版本,所以小明的真实查询应该是这样的
从id<=3和create_version<=3和(delete_version>3或delete_version为null)的用户中选择*;复制代码
所以,小明最后查询到的ID=1的名字还是‘张三',ID=2的记录也可以查询。这样做是为了确保事务读取的数据在事务开始之前就存在,或者由事务本身插入或修改。