【MySQL】一文看懂MySQL所有常见问题

MySQL作为一款开源关系型数据库,如今绝对是占据关系型数据库的主导地位,不仅是面试中的常客,也是日常工作中最主要接触的数据库。因此,无论是背面试八股,还是工作使用,都是一定要深度掌握的一个知识点。今天就用一篇文章讲清楚MySQL的所有问题

着急的小伙伴可直接跳到最后MySQL常见面试题总结

一、事务

定义:一组操作要么全部成功,要么全部失败,目的是为了保证数据最终的一致性

在MySQL中,提供了一系列事务相关的命令:

  • start transaction | begin | begin work:开启一个事务
  • commit:提交一个事务
  • rollback:回滚一个事务

事务的ACID

  • 原子性(Atomicity):当前事务操作要么同时成功,要么同时失败。原子性由undo log日志来保证
  • 一致性(Consistency):使用事务的最终目的,由其他三个特性保证
  • 隔离性(Isolation):事务并发执行时,内部操作互不干扰。InnoDB中隔离性由各种锁和MVCC保证
  • 持久性(Durability):一旦提交事务,它对数据的改变是永久性的。持久性由redo log日志来保证

事务的隔离级别

  • read uncommit(读未提交):处于该隔离级别的数据库,脏读、不可重复读、幻读问题都有可能发生
  • read commit(读已提交):处于该隔离级别的数据库,解决了脏读问题,不可重复读、幻读问题依旧存在
  • repeatable read(可重复读):处于该隔离级别的数据库,解决了脏读、不可重复读问题,幻读问题依旧存在
  • serializable(串行):处于该隔离级别的数据库,以上问题全部解决

脏读、幻读、不可重复读问题

脏读 :读取到其他事务未提交的数据,由于数据还没提交,因此可能产生回滚 幻读 :主要针对插入删除操作来说,比如事务A对全部数据的某一字段做了修改并提交,若事务A提交前,事务B插入了一条数据,事务A再次查询会发现存在修改未生效的数据,如同幻觉 不可重复读 :多次读取同一数据得到不同结果

区别:

  1. 脏读重在指一个事务读到了其他事务未提交的数据。
  2. 不可重复读主要在于一个事务中多次读到同一条数据,但前后读到的结果不一样,这是因为其他事务对数据进行修改并提交导致。
  3. 幻读则是因为被其他事务插入或者删除的数据影响,一个事务内同样条件的数据记录变多或者变少了。

MVCC

MVCC机制的全称为Multi-Version Concurrency Control,即多版本并发控制技术,主要是为了提升数据库并发性能而设计的,其中采用更好的方式处理了读-写并发冲突,做到即使有读写冲突时,也可以不加锁解决,从而确保了任何时刻的读操作都是非阻塞的。

对于使用 InnoDB 存储引擎的数据库表,它的聚簇索引记录中都包含下面两个隐藏列:

  • trx_id,当一个事务对某条聚簇索引记录进行改动时,就会把该事务的事务 id 记录在 trx_id 隐藏列里;
  • roll_pointer,每次对某条聚簇索引记录进行改动时,都会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。

InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

MCC的多版本主要依赖Undo-log日志来实现,而并发控制则通过表的隐藏字段+ReadView快照来实现,通过Undo-log日志、隐藏字段、ReadView快照,就实现了MVCC机制

MySQL中的日志

undo日志

undo log 有两个作用:提供回滚和多个行版本控制(MVCC) undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

  • 执行 rollback 时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
  • 在应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
  • undo log是采用段(segment)的方式来记录的,每个undo操作在记录的时候占用一个undo log segment
  • undo log也会产生redo log,因为undo log也要实现持久性保护。
  • undo 日志一般会在事务提交时被删除,但是如果 undo 日志为 MVCC 服务 则暂时保留
  • 一个事务会产生多个 undo 日志,mysql有专门的 undo 页 保存 undo 日志。innodb 会为每一个事务单独分配 undo 页链表(最多分配 4 个链表)

redo日志

InnoDB独有,用于MySQL崩溃后重启时的数据恢复 更新表数据的时候,如果发现 Buffer Pool 里存在要更新的数据,就直接在 Buffer Pool 里更新。然后会把"在某个数据页上做了什么修改"记录到重做日志缓存(redo log buffer)里,接着刷盘到 redo log 文件里。

刷盘时机

InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数(默认1),它支持三种策略

  1. 设置为0的时候,表示每次事务提交时不进行刷盘操作,只是保留在 redo log buffer中,mysql 崩溃会丢失1s的数据;
  2. 设置为1的时候,表示每次事务提交时都将进行刷盘操作(默认值),持久化到磁盘;
  3. 设置为2的时候,表示每次事务提交时都只把redo log buffer内容写入page cache(OS Buffer),OS宕机会丢失1s的数据,因为未进行持久化;

InnoDB 存储引擎有一个后台线程,每隔1秒,就会把 redo log buffer 中的内容写到文件系统缓存(OS Buffer),然后调用 fsync 刷盘。 redo log buffer占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。

binlog日志

binlog 是归档日志,属于 Server 层的日志,是一个二进制格式的文件,记录内容是语句的原始逻辑,类似于"给 ID=2 这一行的 c 字段加 1"。 不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog 日志。它的主要作用就是数据备份、主从复制。 binlog会记录所有涉及更新数据的逻辑操作,属于逻辑日志,并且是顺序写。

binglog格式

binlog 日志有三种格式,可以通过binlog_format参数指定。

  1. statement :记录的内容是SQL语句原文,存在数据一致性问题;
  2. row:记录包含操作的具体数据,能保证同步数据的一致性;
  3. mixed:记录的内容是前两者的混合,MySQL会判断这条SQL语句是否可能引起数据不一致:如果是,就用row格式,否则就用statement格式。

写入机制

事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。 因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。我们可以通过binlog_cache_size参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap)。 binlog 也提供了 sync_binlog 参数来控制写入 page cache 和磁盘的时机:

  • 0:每次提交事务都只写入到文件系统的 page cache,由系统自行判断什么时候执行fsync,机器宕机,page cache里面的 binlog 会丢失。
  • 1:每次提交事务都会执行fsync,就如同 redo log 日志刷盘流程 一样。
  • N(N>1):每次提交事务都写入到文件系统的 page cache,但累积N个事务后才fsync。如果机器宕机,会丢失最近N个事务的binlog日志。

relay日志

主从同步使用的中继日志,用于存储从master节点同步过来的binlog日志内容

二、索引

索引能快速定位数据的一种数据结构,其设计思想是以空间换时间

1. B+树索引

衍变过程:

  • 二叉树:每个节点包含两个叶子节点,小的在左,大的在右。
    • 缺点:如果数据有序插入,树的高度会增高,降低查询效率,最坏情况是二叉树变成一个链表
  • 红黑树:平衡二叉树,在二叉树的基础上,通过自旋进行平衡,从而减少树的高度。
    • 优点:数据有序插入时性能最高
    • 缺点:随数据量增加,树的高度依然会增加
  • B树:平衡多路查找树,解决二叉树的高度问题,不再限制节点只能为两个;节点中的数据索引从左往右递增排列
    • 优点:降低树的高度,搜索深度降低
    • 缺点:作为存储索引,范围查找的搜索难度大

如下图是一个三阶B树,每个节点存两个数据,并存三个寻址地址指向下一个节点

  • B+树:B树的优化,使其更适合存储索引结构 相对于B树,它做了一下优化
    1. B+树把所有数据都存在了叶子结点,非叶子节点不存数据。减少了每次判断节点时的拿取节点的效率
    2. B+树的叶子节点之间增加了双向指针。提高了范围查找的效率

mysql默认文件页大小是16kb,一个寻址数据大概6b,若存储的是bigint,即8b,那么一块文件页能存储 16kb / (8b + 6b) = 1170个索引;那么一棵三阶B+树,能存储 16x1170x1170≈2000万数据

B树与B+树的区别

  1. B树的所有节点都会存储数据,B+树仅把数据存在叶子节点,而非叶子节点可以存储更多的阶数指针,并且节点不存数据,磁盘IO也会更快
  2. B+树的范围查找,排序查找,分组查找以及去重查找更简单
  3. 数据记录之间通过链表连接,可以很方便的在数据查询后进行升序或降序操作

MySQL中的InnoDB引擎会为每个表创建主键索引,如果表没有明确的主键索引,InnoDB会使用自动生成的隐藏的主键(RowId)来创建索引

2. Hash索引

Hash索引即哈希结构索引,数据结构和Java的HashMap差不多,是数组加链表的形式 InnoDB不支持显示创建Hash索引,只支持自适应Hash索引。仅memory引擎支持hash索引,memory引擎运行于内存中。

• 优点:等值比较效率高 • 缺点:不支持范围查询,也不支持排序,因为索引列无序

3. 聚集索引和非聚集索引

按物理存储方式分类:InnoDB使用聚集索引,MyISAM使用非聚集索引 创建两个测试数据表test_innodb(使用InnoDB引擎)和test_myisam(使用MyISAM引擎),最终在mysql的服务器目录下看到的文件如下:

shell 复制代码
-rw-r----- 1 mysql mysql  114688 Oct 31 11:30 test_innodb.ibd     
-rw-r----- 1 mysql mysql       0 Oct 31 11:31 test_myisam.MYD     
-rw-r----- 1 mysql mysql    1024 Oct 31 11:31 test_myisam.MYI   
-rw-r----- 1 mysql mysql    1653 Oct 31 11:31 test_myisam_491.sdi  

InnoDB仅用一个文件ibd存储了索引和数据 MyISAM分为了三个文件,MYD存储表数据,MYI存储表索引,sdi存储表元数据 MyISAM的叶子节点存储的不是数据,而是数据对应的磁盘指针 InnoDB的主键索引的叶子节点存储的表的所有列,非主键索引的叶子结点存储的表的主键

因此InnoDB是聚集索引,MyISAM是非聚集索引

• 聚集索引优点:因为所有数据都存在B+树的叶子节点,因此可以减少一个数据的查询,提高了查询效率 • 聚集索引缺点:对数据进行修改删除操作时需要更新索引树,增加系统开销,非聚集索引可以避免这个缺陷

4. 二级索引

所有非主键索引均为二级索引,InnoDB中二级索引采用非聚集索引

如上所示,我们对一个age字段进行二级索引,最终得到数据时ID主键,我们需要再根据ID主键去查找数据(回表),这也是非聚集索引

sql 复制代码
SELECT * FROM `user` WHERE age = 17;

比如上面sql,首先会通过age=17这个条件在age的二级索引中找到id7,然后再用id7去ID索引去查找对应的数据

5. 覆盖索引

还是比如上面的sql,若使用select *,那么在通过二级索引找到id后,还需要到id索引找到数据列,假如对上述sql优化如下

sql 复制代码
SELECT id FROM `user` WHERE age = 17;

那么在age的二级索引的数据中,就已经有了id列,不再需要回表查询这个ID对应的所有数据,这种情况叫覆盖索引,即索引结果包含了所有所需的数据。 覆盖索引也是sql优化中的一个手段

6. 索引下推

是MySQL5.6针对扫描二级索引的优化,用于减少范围查询时的回表次数。

sql 复制代码
SELECT * FROM `user` WHERE age > 10 AND age < 20;

比如在这次查询中,我们查到5个人年龄在10到20之间,如果没有索引下推,即会产生5次回表查询来获取所有数据。索引下推即让5次回表合并为一次回表查询。

7. 单列索引和联合索引

• 单列索引:只有一个字段的索引 • 联合索引:有多个字段的索引 在联合索引时,多个字段会存在同一个索引页(B+树节点)中,并且会以优先级按第一个字段,第二个字段,第N字段组合排序

最左前缀原则

在联合索引时,SQL查询需要遵循最左前缀原则,假如建立name和age字段的联合索引。如果我们查询条件只查第二个索引字段age,而不查第一个索引字段name,那么在扫描时,是无序的,只能做全盘扫描,比如以下例子: 以下SQL会执行全盘扫描

sql 复制代码
SELECT * FROM `user` WHERE age=15;

而以下SQL则会快速定位索引

sql 复制代码
SELECT * FROM `user` WHERE name='张三' AND age=15;

联合索引优势

  1. 减少开销 假如有三个字段abc需要建立索引,分别建立三个索引比建立一个索引的开销更大,因为它会创建3个B+树,并且每次插入删除操作都要操作3个B+树。而建立一个联合索引相当于建立了(a)(a,b)(a,b,c)三个索引。对于大数据量的表来说,使用联合索引会大大减少开销。
  2. 覆盖索引 对于联合索引(a,b,c),如有sql
sql 复制代码
SELECT a,b,c FROM table WHERE a='xxx' AND b='XX'; 

那么MySQL可以通过索引直接得到数据而省略回表操作,提高IO性能

  1. 效率高 索引列多,通过联合索引筛选出的数据越少

8. 索引优缺点及适合场景

  • 索引优点:
    1. 提高检索效率
    2. 降低排序成本,索引对应字段可以自动排序,默认升序ASC
  • 索引缺点:
    1. 创建索引和维护索引增加成本,并且这种成本随数据量的增加而增加
    2. 索引占用物理空间,数据量越大空间越大
    3. 降低表的增删改效率,每次更新操作都会维护索引表
  • 适合场景:
    1. 频繁作为查询条件的字段应该创建索引
  • 不适合场景:
    1. 字段唯一性太差不适合索引
    2. 更新频繁字段不适合索引
    3. 不在where语句中字段(不会作为查询条件)不适合索引

9. 索引优化

  • 最左前缀原则
    • 联合索引必须包含第一个索引字段,才能让索引生效
    • 查询条件不能跳过联合索引的中间的字段,必须依次加入查询条件

可归纳为:保证查询条件的有序性才能让索引生效

  • 索引列不要函数计算 如果在索引字段上进行了函数计算,则索引失效,进行全表扫描,比如以下场景
sql 复制代码
SELECT * FROM `user` WHERE left(name,2) = '张三';
  • 范围后面的索引全失效 在联合索引的情况下,范围查询会使后面字段无序,造成部分索引失效,比如以下场景
sql 复制代码
SELECT * FROM `user` WHERE name = '张三' AND age > 18 AND position = 0;
  • 覆盖索引不写星 SELECT的字段尽量使用联合索引中的字段

  • 不等空值和or会让索引失效 MySQL中使用不等于(!=或者<>),not in,not exist的时候无法使用索引导致全表扫描,而<,>,<=,>=,MySQL内部优化器会根据检索比例,表大小等因素决定是否使用索引 当SQL的EXPLAIN出现possible keys时,则代表MySQL可能使用索引,可通过FORCE INDEX(idx)来强制使用索引

  • LIKE百分号写最右 等同于最左前缀原则,即字符串也是按照从左往右进行查询,若第一个字母就是百分号,则索引直接失效

  • VAR引号不能丢 若对varchar类型的字段进行索引查找时,不写引号,那么代表需要mysql进行一次类型转换,则相当于进行了函数计算,进而让索引失效

  • 范围查询优化

三、SQL优化

1. 避免SELECT星号

  • 增加查询分析器解析成本
  • 增加字段容易与resultMap配置不一致
  • 无用字段增加网络消耗,尤其text字段
  • 应用层增加无用字段的反序列化解析
  • SELECT * 查询不走覆盖索引,造成大量回表查询

2. 小表驱动大表

小表驱动大表指用数据量小、索引完备的表,使用其索引和条件对大表进行数据筛选,从减少数据计算量,提高查询效率。

3. 连接查询代替子查询

  • 子查询需要执行两次数据库查询,一次外部查询,一次嵌套子查询。因此使用连接查询可以减少数据库查询次数,提高查询效率。
  • 连接查询可以更好利用索引,提高查询性能。子查询通常会使用临时表或内存表,而连接查询可以直接用表上的索引。
  • 子查询通常需要扫描整个表,而连接查询可以利用索引加速查询效率

4. 提升group by效率

创建group by的字段的索引

5. 批量插入

有多条插入语句时,可通过SQL进行批量插入,减少数据库IO次数 INSERT INTO user(id,name,age) VALUES(1,'张三',18),(1,'李四',20),(1,'王五',25),(1,'赵六',30);

6. 使用limit

  • 提高查询效率:一次查询数据量过多,会占用大量系统资源
  • 避免过度提取数据:对应用层来说,过多的数据量也可能造成应用层的内存和CPU的异常
  • 优化分页查询:查询需要的数据行,减少资源浪费
  • 简化查询结果
  • limit后不宜用过大的数字
  • 比如limit 10000,,10MySQL使用limit查询的逻辑会先从第一条遍历到第10000条,然后再往后偏移10条

7. union all代替union

  • union all:获取所有数据不去重,包含重复数据
  • union:获取所有数据且去重,不包含重复数据

如果没有去重需求,直接优化为union,如果有去重需求,尽量再查询条件去重

8. 尽量少join关联表

  • 查询效率下降:多表join对比时间变长
  • 系统负载增加:join操作需要大量计算,导致系统负载增加
  • 维护难度加大

四、MySQl常见面试题

1. 数据库三大范式

  • 第一范式(1NF):属性不可分割,即每个属性都是不可分割的原子项。(实体的属性即表中的列)
  • 第二范式(2NF):满足第一范式;且不存在部分依赖,即非主属性必须完全依赖于主属性。(主属性即主键;完全依赖是针对于联合主键的情况,非主键列不能只依赖于主键的一部分)
  • 第三范式(3NF):满足第二范式;且不存在传递依赖,即非主属性不能与非主属性之间有依赖关系,非主属性必须直接依赖于主属性,不能间接依赖主属性。(A -> B, B ->C, A -> C)

2. DML 语句和 DDL 语句区别

  • DML 是数据库操作语言(Data Manipulation Language)的缩写,是指对数据库中表记录的操作,主要包括表记录的插入、更新、删除和查询。
  • DDL (Data Definition Language)是数据定义语言的缩写,简单来说,就是对数据库内部的对象进行创建、删除、修改的操作语言。它和 DML 语言的最大区别是 DML 只是对表内部数据的操作,而不涉及到表的定义、结构的修改,更不会涉及到其他对象。

3. drop、delete、truncate 区别

  • 用法区别:
    • drop(丢弃数据): drop table 表名 ,直接将表结构都删除掉,在删除表的时候使用。
    • truncate (清空数据) : truncate table 表名 ,只删除表中的数据,再插入数据的时候自增长 id 又从 1 开始,在清空表中数据的时候使用。
    • delete(删除数据) : delete from 表名 where 列名=值,删除某一行的数据,如果不加 where 子句和truncate table 表名作用类似。
  • 数据库语言区别:truncate和drop是DDL语言,delete是DML语言
  • 执行速度区别:
    • delete命令执行的时候会产生数据库的binlog日志,而日志记录是需要消耗时间的,但是也有个好处方便数据回滚恢复。
    • truncate命令执行的时候不会产生数据库日志,因此比delete要快。除此之外,还会把表的自增值重置和索引恢复到初始大小等。
    • drop命令会把表占用的空间全部释放掉。

4. MyISAM 和 InnoDB 的区别

区别 MyISAM InnoDB
最小锁粒度 表级锁 行级锁
外键 不支持 支持
索引 B+树非聚集索引 B+树聚集索引
主键 可以没有 若没有主键会自动生成隐藏主键Row_id
事务 不支持 支持
异常崩溃恢复 不支持 可根据redo日志在重启后恢复

5. 什么是redo日志

InnoDB独有,用于MySQL崩溃后重启时的数据恢复 更新表数据的时候,如果发现 Buffer Pool 里存在要更新的数据,就直接在 Buffer Pool 里更新。然后会把"在某个数据页上做了什么修改"记录到重做日志缓存(redo log buffer)里,接着刷盘到 redo log 文件里。

刷盘时机

InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数(默认1),它支持三种策略

  1. 设置为0的时候,表示每次事务提交时不进行刷盘操作,只是保留在 redo log buffer中,mysql 崩溃会丢失1s的数据;
  2. 设置为1的时候,表示每次事务提交时都将进行刷盘操作(默认值),持久化到磁盘;
  3. 设置为2的时候,表示每次事务提交时都只把redo log buffer内容写入page cache(OS Buffer),OS宕机会丢失1s的数据,因为未进行持久化; InnoDB 存储引擎有一个后台线程,每隔1秒,就会把 redo log buffer 中的内容写到文件系统缓存(OS Buffer),然后调用 fsync 刷盘。 redo log buffer占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。

6. 什么是binlog日志

binlog 是归档日志,属于 Server 层的日志,是一个二进制格式的文件,记录内容是语句的原始逻辑,类似于"给 ID=2 这一行的 c 字段加 1"。 不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog 日志。它的主要作用就是数据备份、主从复制。 binlog会记录所有涉及更新数据的逻辑操作,属于逻辑日志,并且是顺序写。

binglog格式

binlog 日志有三种格式,可以通过binlog_format参数指定。

  1. statement :记录的内容是SQL语句原文,存在数据一致性问题;
  2. row:记录包含操作的具体数据,能保证同步数据的一致性;
  3. mixed:记录的内容是前两者的混合,MySQL会判断这条SQL语句是否可能引起数据不一致:如果是,就用row格式,否则就用statement格式。

写入机制

事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。 因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。我们可以通过binlog_cache_size参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap)。

binlog 也提供了 sync_binlog 参数来控制写入 page cache 和磁盘的时机:

  • 0:每次提交事务都只写入到文件系统的 page cache,由系统自行判断什么时候执行fsync,机器宕机,page cache里面的 binlog 会丢失。
  • 1:每次提交事务都会执行fsync,就如同 redo log 日志刷盘流程 一样。
  • N(N>1):每次提交事务都写入到文件系统的 page cache,但累积N个事务后才fsync。如果机器宕机,会丢失最近N个事务的binlog日志。

7. binlog和redolog区别

  • redolog 是 Innodb 独有的日志,而 binlog 是 server 层的,所有的存储引擎都有使用到;
  • redolog 记录了具体的数值,对某个页做了什么修改,binlog 记录的操作内容;
  • binlog 大小达到上限或者 flush log 会生成一个新的文件,而 redolog 有固定大小只能循环利用;
  • binlog 日志没有 crash-safe 的能力,只能用于归档,而 redo log 有 crash-safe 能力;
  • redo log 在事务执行过程中可以不断写入(刷盘设置为1,后台线程1s执行一次或者 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候),而 binlog 只有在提交事务时才写入文件缓存系统;

8. 什么是undo日志

MySQL中所有的事务中进行的修改都记录到undo日志,若需要进行回滚,则通过undo日志进行回滚

9. 什么是relay日志

主从同步使用的中继日志,用于存储从master节点同步过来的binlog日志内容

10. 什么是Hash索引

Hash索引即哈希结构索引,数据结构和Java的HashMap差不多,是数组加链表的形式 InnoDB不支持显示创建Hash索引,只支持自适应Hash索引。仅memory引擎支持hash索引,memory引擎运行于内存中。 • 优点:等值比较效率高 • 缺点:不支持范围查询,也不支持排序,因为索引列无序

11. B树和B+树的区别

  1. B树的所有节点都会存储数据,B+树仅把数据存在叶子节点,而非叶子节点可以存储更多的阶数指针,并且节点不存数据,磁盘IO也会更快
  2. B+树的范围查找,排序查找,分组查找以及去重查找更简单
  3. 数据记录之间通过链表连接,可以很方便的在数据查询后进行升序或降序操作

12. 什么是最左前缀原则

最左前缀原则即在有联合索引的查询中,where条件必须按照联合索引字段的顺序依次查询,才能有效利用索引

13. 什么是聚簇索引和非聚簇索引

聚簇索引即B+树种存储索引和数据 非聚簇索引在B+树种存储索引,而完整数据存在其他地方 MyISAM使用非聚簇索引,InnoDB的主键索引使用聚簇索引,非主键索引使用非聚簇索引

14. 索引失效有哪些情况

  1. 没有使用索引列作为where的查询条件
  2. 对索引列进行函数操作(字符串或日期操作)
  3. 对索引列进行类型转换
  4. LIKE查询字符串以通配符开头
  5. or条件查询
  6. 查询条件涉及大量数据

15. 什么是索引下推

索引条件下推,是防止明明可以在存储引擎层判断,但还回表查询后拿到server层判断,减少回表次数。它是MySQL的内部优化,将判断where条件从server层下推到存储引擎层,也就是说存储引擎层也会判断查询其他条件

sql 复制代码
#ON表示已开启
show variables like 'log_bin_trust%';

16. mysql索引类型normal,unique,full text的区别是什么?

  • normal:表示普通索引
  • unique:表示唯一的,不允许重复的索引,如果该字段信息保证不会重复例如身份证号用作索引时,可设置为unique
  • full text: 表示 全文搜索的索引。 FULLTEXT 用于搜索很长一篇文章的时候,效果最好。用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。

17. 事务的特性

事务的特性: A:原子性(Atomicity),原子性是指事务是一个不可分割的工作单位,事务中的操作,要么都发生,要么都不发生。 C:一致性(Consistency),在一个事务中,事务前后数据的完整性必须保持一致。 I:隔离性(Isolation),存在于多个事务中,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。 D:持久性(Durability),持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

18. 事务的隔离级别

为了解决以上隔离性引发的并发问题,数据库提供了事务的隔离机制。

  1. read uncommitted(读未提交): 一个事务还没提交时,它做的变更就能被别的事务看到,读取尚未提交的数据,哪个问题都不能解决;
  2. read committed(读已提交):一个事务提交之后,它做的变更才会被其他事务看到,读取已经提交的数据,可以解决脏读(oracle默认的);
  3. repeatable read(可重复读):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的,可以解决脏读和不可重复读 (mysql默认的);
  4. serializable(串行化):顾名思义是对于同一行记录,"写"会加"写锁","读"会加"读锁"。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。可以解决脏读、不可重复读和虚读---相当于锁表。 虽然 serializable 级别可以解决所有的数据库并发问题,但是它会在读取的每一行数据上都加锁,这就可能导致大量的超时和锁竞争问题,从而导致效率下降。所以我们在实际应用中也很少使用 serializable,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。

19. 为什么不要使用长事务

  1. 并发情况下,数据库连接池容易被撑爆
  2. 容易造成大量的阻塞和锁超时,长事务还占用锁资源,也可能拖垮整个库
  3. 执行时间长,容易造成主从延迟
  4. 回滚所需要的时间比较长,事务越长整个时间段内的事务也就越多
  5. undolog 日志越来越大,长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

20. 查询方法是否需要开启事务

若采用隔离级别是可重复读,如不开启事务,多次sql的查询的时间维度不同,如开启事务则能保证多条sql的结果集处于同一个时间维度。开启不开启具体看业务场景。

21. MySQL中什么情况适合建立索引,什么情况不适合建立索引

  1. 频繁查询的字段适合建立索引
  2. 更新频繁的字段不适合建立索引
  3. 不进行查询的字段不适合索引
  4. 字段唯一性太差不适合索引

22. 为什么不建议使用Select *

  1. 只查询必要的字段,可以减少字段序列化,减少查询对象大小
  2. 如果查询条件是索引列,且只需要查询索引列,只select需要的字段可以避免索引回表查询

23. 说说MySQL InnoDB事务的原理

InnoDB中事务靠ACID特性来保证

  • 原子性(Atomicity):当前事务操作要么同时成功,要么同时失败。原子性由undo log日志来保证
  • 一致性(Consistency):使用事务的最终目的,由其他三个特性保证
  • 隔离性(Isolation):事务并发执行时,内部操作互不干扰。InnoDB中隔离性由各种锁和MVCC保证
  • 持久性(Durability):一旦提交事务,它对数据的改变是永久性的。持久性由redo log日志来保证

并通过四种读未提交、读已提交、可重复读和串行化四种事务隔离级别,来分别解决脏读、幻读、不可重复读问题。四种隔离级别从前往后安全级别越来越高,性能越来越低。 一般情况下,隔离级别采用读已提交(Oracle默认)或可重复读(MySQL默认),具体要根据业务使用场景判断。

关于隔离级别详细信息参考上面原文

24. 一条更新SQL的执行过程

  1. 加载对应id的数据的整页数据到缓存池
  2. 旧值写入undo log,便于回滚
  3. 更新内存数据
  4. 写redo log到redo buffer
  5. redo log顺序写入磁盘,准备提交事务(prepare阶段)
  6. 准备提交事务,binlog写入磁盘
  7. 写入commit标记到redo log文件,提交事务完成;该标记为了保证事务提交后redo log和bin log数据一致
  8. 系统空闲时,随机写入磁盘,以page页为单位写入
  9. 数据更新完成

欢迎关注(w)Henry游戏开发(x) ,分享开发技术!

相关推荐
mqiqe1 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
工业甲酰苯胺1 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
BestandW1shEs1 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师1 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球1 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...1 小时前
表的操作(MySQL)
数据库·mysql·表的操作
哥谭居民00011 小时前
MySQL的权限管理机制--授权表
数据库
2401_857610031 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
wqq_9922502771 小时前
ssm旅游推荐系统的设计与开发
数据库·旅游