请你说说MySQL的事务隔离级别
为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、 Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题
| 隔离级别 | 并发问题 |
|---|---|
| 读未提交 | 可能会导致脏读、幻读或不可重复读 |
| 读已提交 | 可能会导致幻读或不可重复读 |
| 可重复读 | 可能会导致幻读 |
| 可串行化 | 不会产⽣⼲扰 |
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数 据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致 的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
Mysql 默认采用的 REPEATABLE_READ(可重复读)隔离级别 ,Oracle 默认采用的 READ_COMMITTED(读已提交)隔离级别
解决幻读的方法
- 1、数据库的隔离级别默认是可重复读,可能导致幻读问题,可以将级别调整为可串行化。但是效率会大大降低
2、使用MVCC解决快照幻读问题(如简单select),读取的不是最新的数据。维护一个字段作为version,这样可以控制到每次只能有一个人更新一个版本。
select id from table_xx where id = ? and version = Vupdate id from table_xx where id = ? and version = V+1
3、如果需要读最新的数据,可以通过GapLock+Next-KeyLock可以解决当前读幻读问题
select id from table_xx where id > 100 for update;select id from table_xx where id > 100 lock in share mode;
请你说说innodb和myisam的区别?
InnoDB是具有事务、回滚和崩溃修复能力的事务安全型引擎,它可以实现行级锁来保证高性能的大量数据中的并发操作;MyISAM是具有默认支持全文索引、压缩功能及较高查询性能的非事务性引擎。具体来说,可以在以下角度上形成对比:
事务:InnoDB支持事务;MyISAM不支持。
- 数据锁:InnoDB支持行级锁;MyISAM只支持表级锁。
- 读写性能:InnoDB增删改性能更优;MyISAM查询性能更优。
- 全文索引:InnoDB不支持(但可通过插件等方式支持);MyISAM默认支持。
- 外键:InnoDB支持外键;MyISAM不支持。
- 存储结构:InnoDB在磁盘存储为一个文件;MyISAM在磁盘上存储成三个文件(表定义、数据、索引)。
- 存储空间:InnoDB需要更多的内存和存储;MyISAM支持支持三种不同的存储格式:静态表(默认)、动态表、压缩表。
- 移植:InnoDB在数据量小时可通过拷贝数据文件、备份 binlog、mysqldump工具移植,数据量大时比较麻烦;可单独对某个表通过拷贝表文件移植。
- 崩溃恢复:InnoDB有崩溃恢复机制;MyISAM没有。
-
InnoDB中行级锁是怎么实现的?
InnoDB行级锁是通过给索引上的索引项加锁来实现的。只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。 当表中锁定其中的某几行时,不同的事务可以使用不同的索引锁定不同的行。另外,不论使用主键索引、唯一索引还是普通索引,InnoDB都会使用行锁来对数据加锁。
请你说说MySQL索引,以及它们的好处和坏处
索引就像指向表行的指针,是一种允许查询操作快速确定哪些行符合WHERE子句中的条件,并检索到这些行的其他列值的数据结构; 索引主要有普通索引、唯一索引、主键索引、外键索引、全文索引、复合索引几种;
在大数据量的查询中,合理使用索引的优点非常明显,不仅能大幅提高匹配where条件的检索效率,还能用于排序和分组操作的加速。 索引如果使用不当也有比较大的坏处:比如索引必定会增加存储资源的消耗;同时也增大了插入、更新和删除操作的维护成本,因为每个增删改操作后相应列的索引都必须被更新。只要创建了索引,就一定会走索引吗?
不一定。 比如,在使用组合索引的时候,如果没有遵从“最左前缀”的原则进行搜索,则索引是不起作用的。 举例,假设在id、name、age字段上已经成功建立了一个名为MultiIdx的组合索引。索引行中按id、name、age的顺序存放,索引可以搜索id、(id,name)、(id, name, age)字段组合。如果列不构成索引最左面的前缀,那么MySQL不能使用局部索引,如(age)或者(name,age)组合则不能使用该索引查询。
请你讲讲B树和B+树
它们都是平衡多路查找树,是在二叉查找树基础上的改进数据结构。在二叉查找树上查找一个数据时,最坏情况的查找次数为树的深度,当数据量很大时,查询次数可能还是很大,造成大量的磁盘IO,从而影响查询效率;
为了减少磁盘IO的次数,必须降低树的深度,因此在二叉查找树基础上将树改成了多叉加上一些限制条件,就形成了B树;
B+树是B树的变种,区别主要是: 对于k阶的B树,每个中间节点只存k-1个值k个指针,而B+树存k个值和k个指针;
- B树中所有节点中值的总集是全部关键字集合,而B+树中所有叶子节点值的总集就是全部关键字集合;
- B+树为所有叶子节点增加了链接,从而实现了快速的范围查找;
B+树由B树和索引顺序访问方法演化而来,它是为磁盘或其他直接存取辅助设备设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶子节点,各叶子节点通过指针进行链接。
B+树索引在数据库中的一个特点就是高扇出性,例如在InnoDB存储引擎中,每个页的大小为16KB。在数据库中,B+树的高度一般都在2~4层,这意味着查找某一键值最多只需要2到4次IO操作,这还不错。因为现在一般的磁盘每秒至少可以做100次IO操作,2~4次的IO操作意味着查询时间只需0.02~0.04秒。
MySQL主从同步是如何实现的?
- 主服务器(master)把数据更改记录到二进制日志(binlog)中。
- 从服务器(slave)把主服务器的二进制日志复制到自己的中继日志(relay log)中。
- 从服务器重做中继日志中的日志,把更改应用到自己的数据库上,以达到数据的最终一致性。 复制的工作原理并不复杂,其实就是一个完全备份加上二进制日志备份的还原。不同的是这个二进制日志的还原操作基本上实时在进行中。这里特别需要注意的是,复制不是完全实时地进行同步,而是异步实时。这中间存在主从服务器之间的执行延时,如果主服务器的压力很大,则可能导致主从服务器延时较大。
请你说说数据库索引的底层数据结构
索引可选的底层数据机构包括: - 二叉树 - 红黑树 - hash - B-tree 但mysql索引的底层用的并不是二叉树和红黑树。因为二叉树和红黑树在某些场景下都会暴露出一些缺陷。
首先,二叉树在某些场景下会退化成链表,而链表的查找需要从头部开始遍历,而这就失去了加索引的意义。
不使用红黑树的原因是:红黑树作为底层数据结构在面对在些表数据动辄数百万数千万的场景时,会导致索引树的层数很高。索引从根节点开始查找,而如果我们需要查找的数据在底层的叶子节点上,那么树的高度是多少,就要进行多少次查找,数据存在磁盘上,访问需要进行磁盘IO,这会导致效率过低;
而B+树由B树和索引顺序访问方法演化而来,它是为磁盘或其他直接存取辅助设备设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶子节点,各叶子节点通过指针进行链接。 B+树索引在数据库中的一个特点就是高扇出性,例如在InnoDB存储引擎中,每个页的大小为16KB。在数据库中,B+树的高度一般都在2~4层,这意味着查找某一键值最多只需要2到4次IO操作,这还不错。因为现在一般的磁盘每秒至少可以做100次IO操作,2~4次的IO操作意味着查询时间只需0.02~0.04秒。请你说说聚簇索引和非聚簇索引
两者主要区别是数据和索引是否分离。聚簇索引是将数据与索引存储到一起,找到索引也就找到了数据;而非聚簇索引是将数据和索引存储分离开,索引树的叶子节点存储了数据行的地址。 在InnoDB中,一个表有且仅有一个聚簇索引(因为原始数据只留一份,而数据和聚簇索引在一起),并且该索引是建立在主键上的,即使没有指定主键,也会特殊处理生成一个聚簇索引;其他索引都是辅助索引,使用辅助索引访问索引外的其他字段时都需要进行二次查找。 而在MyISAM中,所有索引都是非聚簇索引,叶子节点存储着数据的地址,对于主键索引和普通索引在存储上没有区别。
在InnoDB存储引擎中,可以将B+树索引分为聚簇索引和辅助索引(非聚簇索引)。无论是何种索引,每个页的大小都为16KB,且不能更改。 聚簇索引是根据主键创建的一棵B+树,聚簇索引的叶子节点存放了表中的所有记录。辅助索引是根据索引键创建的一棵B+树,与聚簇索引不同的是,其叶子节点仅存放索引键值,以及该索引键值指向的主键。也就是说,如果通过辅助索引来查找数据,那么当找到辅助索引的叶子节点后,很有可能还需要根据主键值查找聚簇索引来得到数据,这种查找方式又被称为书签查找。因为辅助索引不包含行记录的所有数据,这就意味着每页可以存放更多的键值,因此其高度一般都要小于聚簇索引。请你说说数据库引擎有哪些,各自有什么区别
- InnoDB 引擎是 MySQL 的事务安全(ACID 兼容)存储引擎,具有提交、回滚和崩溃恢复功能来保护用户数据;行级锁定读取增加了多用户并发性和性能;将用户数据存储在聚集索引中,以减少基于主键的常见查询的 I/O;还支持 FOREIGN KEY 维护数据完整性。
- MyISAM引擎的表占用空间较小,表级锁定限制了读/写工作负载的性能,因此它通常用于只读或以读取为主的场景。
- Memory引擎是将所有数据存储在 RAM 中,以便在需要快速查找非关键数据的环境中进行快速访问,以前被称为 HEAP 引擎。
- Archive引擎非常适合存储大量的独立的,作为历史记录的数据,因为它们不经常被读取。它 拥有高效的插入速度,但其对查询的支持相对较差。 Cluster/NDB是高冗余的存储引擎,用多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大,安全和性能要求高的应用。
- Federated引擎提供连接单独的 MySQL 服务器,从多个物理服务器创建一个逻辑数据库的能力,非常适合分布式或数据集市环境。
数据库为什么不用红黑树而用B+树?
AVL树和红黑树基本都是存储在内存中才会使用的数据结构。而数据库中的数据的索引会非常大,所以为了减少内存的占用,索引会被存储到磁盘文件中,此时影响数据库查询效率的主要因素就是磁盘的IO次数。AVL树和红黑树由于一个父节点只能存储两个子节点。所以使用AVL树或红黑树存储大规模数据时,树的深度就会很深,此时磁盘的IO次数也会大幅度增加。B+树中一个父节点有多个子节点,减少了树的深度,磁盘IO次数也相应的减少请你介绍一下数据库的ACID
- 原子性
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
回滚可以用回滚日志(Undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
- 一致性
数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对同一个数据的读取结果都是相同的。
- 隔离性
一个事务所做的修改在最终提交以前,对其他事务是不可见的。
- 持久性
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
系统发生崩溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。
事务的 ACID 特性概念简单,但不是很好理解,主要是因为这几个特性不是一种平级关系:
- 只有满足一致性,事务的执行结果才是正确的。
- 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
- 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对系统崩溃的情况。
请你说说数据库的索引是什么结构,为什么不用哈希表
MySQL中的索引B+树实现的; 哈希表的查询效率的确最高,时间复杂度O(1),但是它要求将所有数据载入内存,而数据库存储的数据量级可能会非常大,全部载入内存基本上是不可能实现的; B+树可以分段加载需要的节点数据,可以在内存资源有限的前提下,极大提高查询效率请你说说InnoDB的MVCC
MVCC:全称为多版本并发控制,逻辑上保持一个数据的多个版本,使得读写操作没有冲突;
- MVCC主要是提高数据库并发性能,用更好的方式去处理读写冲突,做到即使有读写冲突时,也能不加锁,并阻塞并发读,它是一种用来解决读写冲突的无锁并发控制机制,在并发读写数据库时,可以做到在读操作时不用阻塞写操作,在写操作时不用阻塞读操作,提高了数据库并发读写的性能,还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题;
- InnoDB存储引擎默认的隔离级别是不可重复读,不可重复读解决了脏读,不可重复读,幻读等问题,使用的是MVCC,InnoDB实现了MVCC,多个版本的数据可以共存:
- 隐藏列:InnoDB每行数据中都有隐藏列,隐藏列中包含了本行数据的事务id,指向undo log的指针等;
- 基于undo log的版本链:每行数据的隐藏列中包含了指向undo log的指针,而每条undo log指向了更高级的undo log,从而形成了undo log的版本链;
- ReadView:通过隐藏列和版本链,MySQL可以将数据恢复到指针版本,但是具体恢复到哪个版本,需要根据ReadView确定; ReadView:指事务在某个时刻给整个事务系统打快照,之后在进行读写操作时,会将读取到的数据中的事务id于trx_sys快照比较,从而判断数据对该ReadView是否可见,即对事务是否可见。
请你说说乐观锁和悲观锁
乐观锁:乐观锁总是假设最好的情况,每次去拿数据的时候默认别人不会修改,所以不会上锁,只有当更新的时候会判断一下在此期间有没有人更新了这个数据。适用于多读,可以使用版本号机制进行控制
悲观锁:悲观锁总是假设最坏的情况,每次去拿数据是都认为别人会修改,所以每次在拿数据时都会上锁,这样别人想拿这个数据时会阻塞直到拿到锁。mysql数据库的共享锁和排他锁都是悲观锁的实现。
