MySql-高频面试问题

251 阅读18分钟

Mysql

1.索引的种类?区别?特点?优点?缺点?

索引的本质是数据结构。你可以简单理解为“排好序的快速查找数据结构”。

常见的有两类:

(1)哈希,例如HashMap,查询/插入/修改/删除的平均时间复杂度都是O(1);

(2)树,例如平衡二叉搜索树,查询/插入/修改/删除的平均时间复杂度都是O(log2N);

注:InnoDB不支持哈希索引。 虽然哈希索引是 O(1),树索引是 O(log(n)),但 SQL 有很多“有序”需求,故数据库使用树型索引

普通二叉树

概念

  • 从根节点出发,每个节点最多拥有两个子节点

  • 没有子节点的节点叫叶子节点

  • 特点:左节点比根节点小,右节点比根几点大

优点:

  • 有序

  • 查找某个值每次都能淘汰掉50%

场景

  • 适合于范围查找

  • 适合排序

缺点:

当数据过多的时候会变的很高,树会退化,搜索的效率越来越低

平衡二叉树

特点:

  • 自平衡,自动重新选择根节点

优点:

  • 拥有二叉树的全部优点

  • 解决了二叉树的蜕化的问题.降低了树的高度,提升了查询的效率

缺点:

  • 当数据量过大的时候,树的高度依然会很高

平衡树

  • 每一个节点里面都存数据,指针,索引

  • 特点:有序、自平衡、 根节点下面的子节点有多少节点不受限制

B树

又称 平衡的多路搜索树 ,每一个节点

  • 既存储 数据
  • 又存储 指针
  • 还存储 索引

优点

  • 拥有(平衡)树的全部优点
  • 解除了节点和子节点的数量的限制,
  • 从而解决了数据量过大,树过高的问题
  • 自带平衡

缺点

  • 每个节点既保存数据又保存索引and指针,导致每个节点存储的内容是有限的。
  • 从也导致,每次查询数据库的时候,可能存在多次的磁盘IO

B+树

B树的衍生树。MySQL的InnoDB存储引擎的默认索引实现为:B+树索引

特点

  • 除了叶子结点之外的所有节点 都只存储索引+ 指针
  • 所有的数据都存储在叶子节点

优点

  • 每个节点都可以存储更多的索引+ 指针
  • 可以一次性将索引和指针读到内存中去
  • 内存就可以把非叶子结点全部、一次读取到内存中(B+树更适合外部存储)

B树和B+树的区别

2.MySQL的逻辑架构几层?分别是做什么?

Mysql 主要分为Server层和引擎层,Server层主要包括连接器查询缓存分析器优化器执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用。

  1. controller(连接层):负责用户登录认证、鉴权、普通用户会话
  2. service(服务层):管理SQL缓存(MySQL8取消)、检验SQL语法、解析SQL、生成执行计划(Profile)等....
  3. mybatis(引擎层):管理mysql的存储引擎
  4. mysql(存储层/持久层):负责管理硬盘上的存储数据
  • 引擎层是插件式的,目前主要包括,MyISAM,InnoDB,Memory等。

3.SQL语句的解析顺序是怎样的?

查询语句的执行流程如下:

权限校验(如果命中缓存)---》查询缓存---》分析器---》优化器---》权限校验---》执行器---》引擎

更新语句执行流程如下:

分析器----》权限校验----》执行器---》引擎---redo log(prepare 状态---》binlog---》redo log(commit状态)

4.explain关键字常关注的列有哪些?

  1. id: 选择标识符
  2. select_type: 表示查询的类型
  3. table: 输出结果集的表
  4. partitions: 匹配的分区
  5. type: 表示表的连接类型
  6. possible_keys: 表示查询时,可能使用的索引
  7. key: 表示实际使用的索引
  8. key_len: 索引字段的长度
  9. ref: 列与索引的比较
  10. rows: 扫描出的行数(估算的行数)
  11. filtered: 按表条件过滤的行百分比
  12. Extra: 执行情况的描述和说明

5.mysql索引的种类?区别?特点?

  1. 普通/单列索引:即一个索引是只根据一个字段创建的,里面只包含单个列,一个表可以有多个单值索引(也叫单列索引)
  • CREATE INDEX idx_name ON table_name(filed_name)
  1. 联合索引/多值索引:即一个索引包含多个列(也叫多值索引、多列索引)
  • CREATE INDEX idx_name ON table_name(filed_name_1,filed_name_2);
  1. 唯一索引:索引列的值必须唯一,但允许有空值,空值可以有多个
  • CREATE UNIQUE INDEX idx_name ON table_name(filed_name_1,filed_name_2);
  1. 主键索引:设定为主键后数据库会自动建立索引,InnoDB 为聚簇索引 - ALTER TABLE table_name ADD PRIMARY KEY ( filed_name )
  2. 覆盖索引:索引包含所需要的值,不需要“回表”查询, 比如查询 两个字段,刚好是 组合索引 的两个字段
  3. 全文索引: 对内容进行分词搜索,仅可用于Myisam, 更多用ElasticSearch做搜索
  • ALTER TABLE table_name ADD FULLTEXT ( filed_name )

聚簇索引:可以一次直接找到数据

非聚簇索引:聚簇索引之上创建的索引称之为非聚簇索引;非聚簇索引访问数据总是需要二次查找。

回表:从非聚簇索引到聚簇索引的过程。

详解: 在非聚簇索引的叶子节点上存储的并不是真正的行数据,而是主键 ID,所以当我们使用非聚簇索引进行查询时,首先会得到一个主键 ID,然后再使用主键 ID 去聚簇索引上找到真正的行数据,我们把这个过程称之为回表查询。

6.索引失效情况?

  1. 非最左匹配

  2. 错误模糊查询

    • 模糊匹配后面任意字符:like '张%'(生效)
    • 模糊匹配前面任意字符:like '%张'
    • 模糊匹配前后任意字符:like '%张%'
  3. 列运算

    • select * from student where id+1=2(失效)
  4. 使用函数

    • 使用mysql任意的函数就会失效。
    • 例如: select * from student where ifnull(id,0)=1 (失效)
  5. 类型转换

    • 如果索引列在表中是字符型,搜索where条件后是整型,则存在类型转换
  6. 使用 is not null

    • 当在查询中使用了 is not null 也会导致索引失效,而 is null 则会正常触发索引的

最左原则?

  • 顾名思义,就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
  • 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
  • =和in可以被mysql优化调整到前面的位置(被命中),比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

什么叫索引的部分命中和完全命中?

全部命中:索引的列全部匹配从最左开始就是全部命中

部分命中:索引的列从最左开始只按顺序匹配了一两个,然后就从中间断了

7.存储引擎种类有哪些?

MySQL5.7支持的引擎包括:InnoDB、MyISAM、MEMORY、Archive、Federate、CSV。

innoDb

InnoDB的缓冲池缓存什么?有什么用?

缓存表数据与索引数据,把磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用。

大于等于5.5之后,默认采用InnoDB引擎。 在mysql里面是默认引擎,拥有事务.行锁,支持高并发.可以缓存索引和真实数据.没有特别原因优先考虑innoDb引擎

MyISAM

5.5之前默认的存储引擎

有大量特性:全文索引、压缩、空间函数(GIS)等,不支持事务和行级锁 本身是表锁

有个缺陷是崩溃后无法安全恢复

Archive

•      Archive档案存储引擎只支持INSERT和SELECT操作,在MySQL5.1之前不支持索引。

•      Archive表适合日志和数据采集(档案)类应用

CSV

csv引擎可以将数据保存到csv里面 非常做数据迁移

Memory

访问数据快,数据不会被修改,重启后丢失也没关系

innodb和MyIsam的区别

  • 事务和外键

    • InnoDB支持事务和外键,具有安全性和完整性,适合大量insert或update操作。

    • MyISAM不支持事务和外键,它提供高速存储和检索,适合大量的select查询操作

  • 锁机制

    • InnoDB支持行级锁,锁定指定记录。基于索引来加锁实现。[innodb默认是行锁,前提条件是建立在索引之上的。如果筛选条件没有建立索引,会降级到表锁。即如果where条件中的字段都加了索引,则加的是行锁;否则加的是表锁。]
    • MyISAM支持表级锁,锁定整张表。
  • 索引结构

    • InnoDB使用聚簇索引,索引和记录在一起存储,既缓存索引,也缓存记录。可以一次直接找到数据
    • MyISAM使用非聚簇索引,索引和记录分开。建立在聚簇索引之上,必须两次以上完成查找。
  • 并发处理能力

    • InnoDB读写阻塞可以与隔离级别有关,可以采用多版本并发控制(MVCC)来支持高并发。
    • MyISAM使用表锁,会导致写操作并发率低,读之间并不阻塞,读写阻塞。
  • 存储文件

    • InnoDB表对应两个文件,一个.frm表结构文件,一个.ibd数据文件。InnoDB表最大支持64TB;
    • MyISAM表对应三个文件,一个.frm表结构文件,一个MYD表数据文件,一个.MYI索引文件。从MySQL5.0开始默认限制是256TB。
适用场景

InnoDB

  1. 需要事务支持(具有较好的事务特性)
  2. 行级锁定对高并发有很好的适应能力
  3. 数据更新较为频繁的场景
  4. 数据一致性要求较高
  5. 硬件设备内存较大,可以利用InnoDB较好的缓存能力来提高内存利用率,减少磁盘IO

MyISAM

  1. 不需要事务支持(不支持)
  2. 并发相对较低(锁定机制问题)
  3. 数据修改相对较少,以读为主
  4. 数据一致性要求不高

8.mysql数据库的隔离级别有哪些?默认是什么?特点是什么?

读未提交

  • 读未提交: AB两个事务操作数据的时候,A事务可以读取到B事务未提交的操作
  • --->问题: 脏读 不可重复读 幻读

读已提交(oracle的默认级别)

  • 读已提交: AB两个事务操作数据的时候,A事务只能读取到B提交的数据
  • 避免脏读, --->问题: 不可重复读 幻读

可重复读(mysql的默认级别)

  • 可重复读(默认隔离级别): 同一个事务内多次读取同一份数据的内容是一样
  • 避免了脏读,不可重复读, --->问题:很小概率 幻读

串行化

  • 避免所有问题!
  • 读的时候加共享锁,其他事务可以并发读,但是不能写。
  • 写的时候加排它锁,其他事务不能并发写,也不能并发读。
  • 但因为执行效率低,所以真正使用的场景并不多。

9.脏、幻、不可重复读是什么意思?

脏读: A事务操作数据未提交,B事务读取到A事务操作的内容,A事务提交失败!

幻读/虚读: 同一个事务内,同一个查询多次查询到的结果不一样(新增)

不可重复读: 同一个事务内,对同一份数据多次查询到的结果不一样(修改)

怎么解决?

更改事务的隔离级别。

10.SQL怎么优化?

  1. 尽量选择较小的列

select子句中避免使用‘*’

当只需要一行数据的时候使用limit 1

(加上了limit 1,只要找到了一条对应的记录,就不会继续向下扫描了。效率高。 不加limit 1 是全表扫描。)

  1. 索引

将where中用的比较频繁的字段建立索引。

避免在索引列上使用计算、not in 和<>等操作。

避免改变索引列的类型。

  1. 子查询

尽量缩小子查询的结果

  1. 数据量多

保证单表数据不超过200W,适时分割表。针对查询较慢的语句,可以使用explain 来分析该语句具体 的执行情况。

  1. 表顺序

在from子句中包含多个表的情况下,我们选择记录条数最少的表作为基础表。from字句中写在最后的表是基础表,这张表将被最先处理。这也是我们选择最有效的表名顺序的方案。

.乐观锁和悲观锁?

悲观锁(Pessimistic Concurrency Control,PCC):比较悲观,假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。至于怎么加锁,加锁的范围也没讲。

乐观锁(Optimistic Concurrency Control,OCC):比较乐观,假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。也没具体指定怎么检查。

毕竟乐观锁和悲观锁也不仅能用在数据库中,也能用在线程中。

悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好

乐观锁不能解决脏读,加锁的时间要比悲观锁(只是在执行sql时加了基本的锁保证隔离性级别),乐观锁可以用较大的锁粒度获得较好的并发访问性能

但是如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。

可见,乐观锁更适合解决冲突概率极小的情况; 而悲观锁则适合解决并发竞争激烈的情况,尽量用行锁缩小加锁粒度以提高并发处理能力,即便加行锁的时间比加表锁的要长

.默认主从集群数据同步的流程(异步复制)?

  1. 事务提交到master
  2. master接收到应用事务提交请求后,更新内部的binlog日志,让mysql引擎执行事务操作,并返回给客户端执行结果信息。同时在master中会存在一个事件监听,其会一直监听着master中binlog日志文件的改变,一旦发现日志文件发生改变,触发dump线程
  3. dump线程被触发后,通知slave中的IO线程现在有事务操作要进行同步
  4. slave中IO线程接收到通知后,会从slave中relay-log.info文件中获取slave中的binlog日志文件和pos位置信息。接着会把这部分信息发送给master的dump线程
  5. master的dump线程收到这些信息后,会根据slave发送的binlog日志文件和pos位置,将最新的binlog日志和pos位置后面的内容同步给slave的IO线程
  6. slave的IO线程接收到这些信息后,会将这部分内容同步到slave中的relay-bin文件中
  7. 当relay-bin文件发生改变后,触发slave线程执行sql操作【异步】
  8. 当slave向relay-bin写入完成后,会向master返回一个ACK消息,同步成功。

对于这一系列的操作,可以发现master和slave在进行同步时是以异步的方式完成的,master写入完binlog后,会马上通过引擎进行事务提交并向客户端返回响应,对于与slave同步的操作,则是异步完成的。

优点:

效率高

缺点:

可能出现数据不一致(弱一致)

和半同步复制的区别?

  1. 主体流程相似或者说数据的同步的过程一模一样

  2. 半同步复制主节点完成数据存储,同时保证从节点也完成了数据同步以后,才返回给用户结果(强一致)

  3. 异步复制只需要主节点完成数据存储就返回给用户结果(弱一致)

什么叫主主级联模式?

主主级联架构:

所有从服务都丢给主服务1完成数据同步 主服务1不对外提供操作

只有主服务2挂掉了 主服务1才会顶上去

单点问题:靠主主级联架构解决

通过这种架构不仅可以解决master单点的问题,也可以解决slave延迟的问题。

image.png

级联复制: 级联复制

12.什么叫读写分离?

主从服务:

  • 主服务作为写服务
  • 从服务作为读服务

问题:从服务越多,越会影响主服务的性能,因为主服务需要分配大量的资源去完成数据同步

主从级联架构:

主服务下面的从服务还有很多从服务

这样能减少主从服务的从服务数量,让主服务尽量的保证最大的性能给用户做写操作,少量性能作为数据同步

问题:主服务单点 主服务蹦了 就只能做读操作了

.mysql的分片策略有哪些?区别?特点?

取模分片:

当一个数据表中的数据量非常大时,就需要考虑对表内数据进行分片,拆分的规则有很多种,比较简单的一种就是,通过对id进行取模,完成数据分片

问题分析

- 散列不均匀,出现数据倾斜

- 每张表中的数据量差距较大

- 动态扩容时,存在重新计算,出现数据丢失

- 动态扩容后新增表时,需要对模数修改时有可能就会造成当查询某个分片时,在该分片中找不到对应数据

全局id分片:

当进行数据切分后,数据会存放在多张表中,如果仍然通过数据库自增id的方式,就会出现ID重复的问题,造成数据错乱。所以当拆分完数据后,需要让每一条数据都有自己的ID,并且在多表中不能出现重复。比较常见的会使用雪花算法来生成分布式id。

优点:

- 是基于本地文件,本地加载,读取速度较快

缺点:

- MyCAT重新发布后,配置文件中的sequence会初始化

- 生成的id没有意义

- MyCat如果存在多个,会出现id重复冲突

使用过什么分片的工具?

MyCat和ShardingSphere根据具体场景来做。

15.mysql的最小存储单元是什么?默认大小是多少?

  1. mysql的最小存储单元是页,每页的默认大小为16kb(可以更改)2^14b
  2. 每个指针的大小是6kb,每个索引的大小是8kb。一对(索引+指针)=14b(计算方便视为 16b --> 2^4 b)
  3. 每一页可以存储 2^14b/2^4b = 2^10(2^14b/14b) 个索引+指针。

3层高的B+树可以存储1kb的数据多少条?

  1. 假设这个 b+ 树是n阶的,总共有 n^2 个叶子节点
  2. 一个叶子节点,每个容量也是一页 = 16kb,每条数据是1kb,能存16条。 (2^4条)
  3. n^2个节点可以存储 n^2*2^4条数据。 ---- >1024个节点,就能存 2^24条数据
  4. 真实的条数 > 2^24= 16777216 (这里实际索引指针大小是14b,意味着每页能存更多条数据,实际数据当然要大于这里的2^24条) 实际工作中,这里的数据大小100-200b每条,应该是这列1024的5-10倍。