面试题-MySQL篇
MySQL篇
1. MySQL 有哪些存储引擎?
mysql常用引擎包括:MYISAM、Innodb、Memory、MERGE
- MYISAM:全表锁,拥有较高的执行速度,不支持事务,不支持外键,并发性能差,占用空间相对较小,对事务完整性没有要求,以select、insert为主的应用基本上可以使用这引擎
- Innodb:行级锁,提供了具有提交、回滚和崩溃回复能力的事务安全,支持自动增长列,支持外键约束,并发能力强,占用空间是MYISAM的2.5倍,处理效率相对会差一些
- Memory:全表锁,存储在内存中,速度快,但会占用和数据量成正比的内存空间且数据在mysql重启时会丢失,默认使用HASH索引,检索效率非常高,但不适用于精确查找,主要用于那些内容变化不频繁的代码表
- MERGE:是一组MYISAM表的组合
2. InnoDB和MyISAM的区别有哪些?
- InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
- InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
- InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
- InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用
一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快; - Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;
3. 数据库的三范式是什么?
-
第一范式:列不可再分
-
第二范式:行可以唯一区分,(主键约束)
-
第三范式:表的非主属性不能依赖与其他表的非主属性(外键约束)且三大范式是一级一级依赖的,第二范式建立在第一范式上,第三范式建立第一第二范式上
4. 数据库事务
-
什么是事务?:多条sql语句,要么全部成功,要么全部失败
-
事务的特征?:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabiliy)。简称ACID。
-
事务的隔离级别有哪些?:读未提交、读提交、可重复读、串行化。
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
-
MySQL的默认隔离级别是哪个?:可重复读
-
事务的并发问题有哪些?:脏读、不可重复读、幻读。如何解决?:通过设置隔离级别、使用悲观锁、使用乐观锁。
- 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
- 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
- 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
- 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
5. 索引
-
索引是什么
- 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
- 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。
- 我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
-
索引优缺点
- 优点:
- 降低数据排序的成本,降低CPU消耗: 索引之所以查的快是因为先将数据排好序,若该字段正好需要排序,则正好降低了排序的成本
- 提高数据的检案速度,降低数据库IO成本: 使用案引的意义就是通过缩小表中需要查询的记录的数目从而加快搜案的速度
- 缺点:
- 降低更新表的速度: 表的数据发生了变化,对应的索引也需要一起变更从而减低的更新速度,否则索引指向的物理数据可能不对,这也是索引失效的原因之一
- 占用存储空间:索引实际上也是一张表,记录了主键与素引字段股以素引文件的形式存储在磁盘上
- 优点:
-
什么时候不要使用索引?
- 经常增删改的列不要建立索引;
- 有大量重复的列不建立索引;
- 表记录太少不要建立索引。
6. Sql优化手段
- 查询语句中不要使用select * 会进行全表扫描,占用大量资源
- 尽量减少子查询,使用关联查询(left join,right join,inner join)替代
- 减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
- or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
- 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
- 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
7. 什么是内连接、外连接、右外连接、左外连接?
- 内联接(Inner Join):匹配2张表中相关联的记录。
- 左外联接(Left Outer Join):除了匹配2张表中相关联的记录外,还会匹配左表中剩余的记录,右表中未匹配到的字段用NULL表示。
- 右外联接(Right Outer Join):除了匹配2张表中相关联的记录外,还会匹配右表中剩余的记录,左表中未匹配到的字段用NULL表示。在判定左表和右表时,要根据表名出现在Outer Join的左右位置关系。
8. 说说在 MySQL 中一条查询 SQL 是如何执行的?
例如:
1 | select * from user where id = 1; |
- 取得链接,使用使用到 MySQL 中的连接器。
- 查询缓存,key 为 SQL 语句,value 为查询结果,如果查到就直接返回。不建议使用次缓存,在 MySQL 8.0 版本已经将查询缓存删除,也就是说MySQL 8.0 版本后不存在此功能。
- 分析器,分为词法分析和语法分析。此阶段只是做一些 SQL 解析,语法校验。所以一般语法错误在此阶段。
- 优化器,是在表里有多个索引的时候,决定使用哪个索引;或者一个语句中存在多表关联的时候(join),决定各个表的连接顺序。
- 执行器,通过分析器让 SQL 知道你要干啥,通过优化器知道该怎么做,于是开始执行语句。执行语句的时候还要判断是否具备此权限,没有权限就直接返回提示没有权限的错误;有权限则打开表,根据表的引擎定义,去使用这个引擎提供的接口,获取这个表的第一行,判断 id 是都等于 1。如果是,直接返回;如果不是继续调用引擎接口去下一行,重复相同的判断,直到取到这个表的最后一行,最后返回。
9. MySQL 中 varchar 与 char 的区别?varchar(30) 中的 30代表的涵义?
- varchar 与 char 的区别,char 是一种固定长度的类型,varchar 则是一种可变长度的类型。
- varchar(30) 中 30 的涵义最多存放 30 个字符。varchar(30) 和 (130) 存储 hello 所占空间一样,但后者在排序时会消耗更多内存,因为 ORDER BY col 采用 fixed_length 计算 col 长度(memory 引擎也一样)。
- 对效率要求高用 char,对空间使用要求高用 varchar。
10. int(11) 中的 11 代表什么涵义?
- int(11) 中的 11,不影响字段存储的范围,只影响展示效果。
- int(11)是一种数据类型定义。其中int表示整数类型,而括号里的11并不代表存储数字的大小范围。
- 它主要用于在显示宽度上的格式化。例如,当使用ZEROFILL属性时,int(11)表示如果存储的数字位数不足 11 位,会在数字前面填充 0 来达到 11 位的显示宽度。
- 举例来说,如果定义了一个字段为int(11) ZEROFILL,存储数字1时,在查询结果中可能会显示为00000000001。但从存储角度讲,int类型在 MySQL 中有固定的存储范围(通常是-2147483648到2147483647),这个范围与int(11)中的11无关。
11. 为什么 SELECT COUNT(*) FROM table 在 InnoDB 比MyISAM 慢?
对于 SELECT COUNT(*) FROM table 语句,在没有 WHERE 条件的情况下,InnoDB 比 MyISAM 可能会慢很多,尤其在大表的情况下。因为,InnoDB 是去实时统计结果,会全表扫描;而 MyISAM内部维持了一个计数器,预存了结果,所以直接返回即可。
12. 说说 InnoDB 与 MyISAM 有什么区别?
- 在 MySQL 5.1 及之前的版本中,MyISAM 是默认的存储引擎,而在 MySQL 5.5 版本以后,默认使用 InnoDB 存储引擎。
- MyISAM 不支持行级锁,换句话说,MyISAM 会对整张表加锁,而不是针对行。同时,
- MyISAM 不支持事务和外键。MyISAM 可被压缩,存储空间较小,而且 MyISAM 在筛选大量数据时非常快。
- InnoDB 是事务型引擎,当事务异常提交时,会被回滚。同时,InnoDB 支持行锁。此外,
- InnoDB 需要更多存储空间,会在内存中建立其专用的缓冲池用于高速缓冲数据和索引。
- InnoDB 支持自动奔溃恢复特性。
建议:一般情况下,个人建议优先选择 InnoDB 存储引擎,并且尽量不要将 InnoDB 与 MyISAM 混合使用。
13. MySQL 索引类型有哪些?
- 主键索引:索引列中的值必须是唯一的,不允许有空值。
- 唯一索引:索引列中的值必须是唯一的,但是允许为空值。
- 全文索引:只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。MyISAM和InnoDB中都可以使用全文索引。
- 空间索引:MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
- 前缀索引:在文本类型如CHAR,VARCHAR,TEXT类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。
14. MVCC
- 说说什么是 MVCC?
- 多版本并发控制(MVCC=Multi-Version Concurrency Control),是一种用来解决读 - 写冲突的无锁并发控制。也就是为事务分配单向增长的时间戳,为每个修改保存一个版本。版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照(复制了一份数据)。这样在读操作不用阻塞写操作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读。
- MVCC 可以为数据库解决什么问题?
- 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。同时还可以解决脏读、幻读、不可重复读等事务隔离问题,但不能解决更新丢失问题。
- 说说 MVCC 的实现原理
- MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3 个隐式字段、undo 日志、Read View 来实现的。
15. 请说说 MySQL 数据库的锁?
MySQL 中有共享锁和排它锁,也就是读锁和写锁。
- 共享锁:不堵塞,多个用户可以同一时刻读取同一个资源,相互之间没有影响。
- 排它锁:一个写操作阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用
户读取正在写入的资源。 - 表锁:系统开销最小,会锁定整张表,MyISAM 使用表锁。
- 行锁:容易出现死锁,发生冲突概率低,并发高,InnoDB 支持行锁(必须有索引才能实现,否则会自动锁全表,那么就不是行锁了)。
16. 说说悲观锁和乐观锁
- 悲观锁:
- 说的是数据库被外界(包括本系统当前的其他事物以及来自外部系统的事务处理)修改保持着保守态度,因此在整个数据修改过程中,将数据处于锁状态。悲观的实现往往是依靠数据库提供的锁机制,也只有数据库层面提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统汇总实现了加锁机制,也是没有办法保证系统不会修改数据。在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。读取数据时给加锁,其它事务无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。
- 乐观锁:
- 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据
17. 怎样尽量避免死锁的出现?
- 设置获取锁的超时时间,至少能保证最差情况下,可以退出程序,不至于一直等待导致死锁;
- 设置按照同一顺序访问资源,类似于串行执行;
- 避免事务中的用户交叉;
- 保持事务简短并在一个批处理中;
- 使用低隔离级别;
- 使用绑定链接
18. SQL优化经验
- 表的设计优化,数据类型的选择,参考阿里开发手册
- 索引优化,索引创建原则
- sql语句优化,避免索引失效,避免使用select*
- 主从复制、读写分离,不让数据的写入,影响读操作
- 分库分表
19. MySQL中什么时候索引会失效?
- 违反最左前缀法则
- 范围查询右边的列,不能使用索引
- 不要在索引列上进行运算操作,索引将失效
- 字符串不加单引号,造成索引失效。(类型转换)
评论