MySQL原理级别的面试题及答案深入剖析

 更新时间:2026年07月13日 09:11:34   作者:Thomas.Sir  
MySQL 作为主流的数据库,是各大厂面试官百问不厌的知识点,这篇文章主要介绍了MySQL原理级别面试题及答案的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下

试题1:几种常用mysql存储引擎的特点和适用场景?

1. InnoDB

核心特性:支持完整ACID事务、行级锁、外键约束、崩溃恢复机制。
文件结构:.ibd文件(数据+索引)
索引类型:聚簇索引(B+树)
适用场景:电商订单、金融交易、高并发读写系统

2. MyISAM

核心特性:不支持事务、表级锁、读取速度快、支持全文索引。
文件结构:.frm(结构)+.MYD(数据)+.MYI(索引)
索引类型:非聚簇索引(B+树)
适用场景:博客系统、论坛文章列表、静态数据查询

3. Memory

核心特性:数据存储在内存中、读写极快、重启数据丢失。
存储方式:内存存储,仅.frm文件存磁盘
索引类型:哈希索引/B树索引
适用场景:会话数据、临时计算结果、缓存层

  • Archive引擎:采用高压缩比存储,仅支持插入和查询操作,适合日志归档和历史数据存储。
  • CSV引擎:数据以纯文本CSV格式存储,便于与其他系统进行数据交换。
  • Federated引擎:可以访问远程MySQL服务器上的表,实现分布式数据访问。

场景化选型指南:

实战案例解析:

  • 电商订单系统:必须使用InnoDB。订单创建、库存扣减、支付处理都需要事务保证一致性。行级锁能支持高并发秒杀场景。

  • 新闻资讯网站:适合MyISAM。文章发布后很少修改,但读取频率极高。MyISAM的COUNT(*)操作直接从元数据读取,比InnoDB扫描全表快得多。

  • 用户会话管理:Memory引擎是理想选择。会话数据生命周期短,重启丢失影响不大,但读写速度要求极高。

  • 系统操作日志:Archive引擎最合适。日志只增不删,需要高压缩比节省存储空间,查询频率极低。

性能优化与避坑指南:

InnoDB优化策略

缓冲池配置:innodb_buffer_pool_size设置为物理内存的50%-70%,这是最重要的性能参数。

事务管理:保持事务短小精悍,避免长事务占用锁资源。

索引设计:主键使用自增ID,避免聚簇索引页分裂;定期使用ANALYZE TABLE更新统计信息。

MyISAM维护技巧

定期优化:频繁写入后会产生碎片,使用OPTIMIZE TABLE重建表:OPTIMIZE TABLE myisam_table;

备份策略:MyISAM不支持崩溃恢复,必须建立定期备份机制。

并发控制:设置low_priority_updates=ON降低写操作优先级,减少读阻塞。

Memory引擎注意事项

内存限制:表大小受max_heap_table_size控制(默认16MB),需根据数据量调整。

数据类型:不支持TEXT、BLOB等大字段,VARCHAR会转为CHAR浪费空间。

持久化方案:如需数据持久化,可配合InnoDB定期同步,或直接使用Redis。

试题2:说一下 MySQL 的事务?

ACID四大特性:

原子性 (Atomicity)

操作全成功或全失败。通过 Undo Log 实现。当事务回滚时,MySQL会读取Undo Log中的记录,将数据恢复到事务开始前的状态。

一致性 (Consistency)

保证数据完整性。由原子性、持久性和隔离性共同保证,确保事务执行前后数据库状态合法。 

隔离性 (Isolation)

事务间互不干扰。主要通过 MVCC(多版本并发控制) 和 锁机制 实现。MVCC允许读操作不阻塞写操作,而锁机制则用于处理写操作间的冲突。 

持久性 (Durability)

提交后永久保存。通过 Redo Log 实现。采用WAL(Write-Ahead Logging)技术,先将修改记录到Redo Log,再写入内存。当系统崩溃时,重启后可通过Redo Log恢复已提交事务的数据。 

事务隔离级别:

隔离级别越高,数据一致性越强,但并发性能可能越低。

隔离级别脏读不可重复读幻读
READ UNCOMMITTED可能可能可能
READ COMMITTED不可能可能可能
REPEATABLE READ不可能不可能可能 (标准)
SERIALIZABLE不可能不可能不可能

*注:MySQL InnoDB在REPEATABLE READ级别通过Next-Key Lock机制有效避免了幻读。 

事务控制语句:

-- 开启事务
START TRANSACTION;

-- 执行SQL操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 提交事务
COMMIT;

-- 或回滚
ROLLBACK;

实战案例:银行转账

假设从用户A账户转账1000元到用户B账户,必须保证操作原子性。

START TRANSACTION;

-- 从A账户扣款
UPDATE accounts SET balance = balance - 1000 WHERE user_id = 'A';

-- 向B账户存款
UPDATE accounts SET balance = balance + 1000 WHERE user_id = 'B';

-- 记录日志
INSERT INTO transaction_log(from_user, to_user, amount, timestamp) VALUES('A', 'B', 1000, NOW());

-- 提交事务
COMMIT;

试题3:说说 MySQL锁机制?

在数据库高并发场景下,锁是保证数据一致性和事务隔离性的核心机制。MySQL的锁机制主要分为表锁和行锁,它们分别对应不同的并发控制粒度,直接影响着数据库的性能和并发能力。

表锁锁定整张表,实现简单但并发度低;行锁只锁定特定行,并发度高但开销大。理解这两种锁的机制、适用场景以及InnoDB引擎如何实现行锁,是优化数据库性能的关键。

表锁(Table Lock)

锁定整张表,实现简单,开销小,但并发性能差。MyISAM引擎默认使用表锁,InnoDB在特定情况下也会退化为表锁。

工作模式:

• 读锁(共享锁):多个事务可以同时读取同一张表,但会阻塞写操作

• 写锁(排他锁):一个事务获得写锁后,其他事务的读写操作都会被阻塞

行锁(Row Lock)

锁定单行或多行数据,并发度高但开销大,可能引发死锁。InnoDB引擎的核心特性,基于索引实现。它只锁定需要操作的行,而不是整张表,这大大提高了数据库的并发性能。

InnoDB行锁的三种类型:

记录锁(Record Lock)

锁定索引记录本身,是最基本的行锁类型。当一个事务对一条记录加了X型记录锁后,其他事务既不能对该记录加S型记录锁,也不能加X型记录锁。

间隙锁(Gap Lock)

锁定索引记录之间的间隙,防止幻读现象的发生。只存在于可重复读隔离级别,间隙锁之间是兼容的。

临键锁(Next-Key Lock)

Record Lock + Gap Lock的组合,锁定一个范围并且锁定记录本身。InnoDB在可重复读隔离级别下默认使用临键锁防止幻读。

-- 行锁使用示例
START TRANSACTION;
-- 对id=1的记录加排他锁(X锁)
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 其他事务无法修改或锁定这行数据
UPDATE users SET name = 'new_name' WHERE id = 1;
COMMIT;

意向锁:表锁与行锁的协调者

InnoDB支持多粒度锁定,允许事务在行级和表级上同时存在锁。为了实现行锁和表锁的共存,InnoDB设计了意向锁(Intention Lock)

锁类型级别作用兼容性
意向共享锁(IS)表级表示事务打算给表中的某些行加共享锁与IS、IX兼容
意向排他锁(IX)表级表示事务打算给表中的某些行加排他锁与IS、IX兼容
表共享锁(S)表级锁定整张表为只读与IS兼容,与IX不兼容
表排他锁(X)表级锁定整张表为读写与IS、IX都不兼容

意向锁是表级锁,其作用是快速判断表中是否存在行级锁。如果没有意向锁,加"独占表锁"时需要遍历表中所有记录,查看是否有记录存在独占锁,效率会很慢。

意向锁之间是相互兼容的,但意向锁与表级读写锁之间大部分都是不兼容的。这种设计使得InnoDB能够高效地管理不同粒度的锁。

锁的加锁与释放机制:

InnoDB采用两阶段锁定协议(two-phase locking protocol):在事务执行过程中,随时都可以执行加锁操作,但是只有在事务执行COMMIT或者ROLLBACK的时候才会释放锁,并且所有的锁是在同一时刻被释放。

隐式锁定与显式锁定

隐式锁定:对于常见的DML语句(如UPDATE、DELETE和INSERT),InnoDB会自动给相应的记录行加写锁;对于DDL语句(如ALTER、CREATE等),会自动给相应的表加表级锁。

显式锁定:通过特定语句手动加锁,如SELECT ... FOR UPDATE加行级写锁,SELECT ... LOCK IN SHARE MODE加行级读锁。

死锁问题与解决方案:

死锁(Deadlock)指两个或多个事务互相等待对方持有的锁,导致永远等待。行锁由于粒度细,更容易发生死锁,而表锁由于锁定整个表,不会出现死锁情况。

死锁示例场景

--事务1:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance - 50 WHERE user_id = 2;

--事务2:
START TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE user_id = 2;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;

两个事务以相反顺序访问相同资源,互相等待对方释放锁,形成死锁。

死锁解决方案:

1. 死锁检测与自动回滚:InnoDB会自动检测死锁,并回滚其中一个事务。

2. 固定顺序访问资源:所有事务按照相同顺序访问表或行,避免循环等待。

3. 合理设置超时时间:通过innodb_lock_wait_timeout参数设置锁等待超时时间。

4. 尽量使用短事务:减少事务持有锁的时间,降低死锁概率。

高并发优化策略:

在实际应用中,合理使用锁机制可以显著提升数据库性能。以下是一些优化策略:

  • 使用行锁代替表锁:在可能的情况下尽量使用行锁,提高并发性能。
  • 创建合适的索引:确保查询语句能够命中索引,避免行锁退化为表锁。
  • 尽量使用短事务:减少锁的持有时间,降低锁冲突概率。
  • 固定顺序访问资源:避免不同事务以不同顺序访问相同资源,减少死锁发生。
  • 合理使用MVCC:对于只读查询,使用MVCC快照读避免加锁。
-- 优化示例:为WHERE列创建索引,避免全表锁
CREATE INDEX idx_user_id ON account(user_id);

-- 使用行锁的安全转账示例
START TRANSACTION;
-- 使用FOR UPDATE锁定需要修改的行
SELECT balance FROM accounts WHERE user_id = 'A' FOR UPDATE;
-- 检查余额、执行转账操作
UPDATE accounts SET balance = balance - 100 WHERE user_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE user_id = 'B';
COMMIT;

试题四:说说 MySQL 索引?

首先介绍一款可以帮助我们理解数据结构的网站

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

一、数据结构

索引是一种特殊的数据结构。可以帮助我们快速查询到数据。

1、二叉树

二叉树是一种特殊的树,每个节点最多有两个子节点,值从左到右依次递增。

例如:当想查询值为11的数据时,如果没有索引要按顺序查找多次,有索引只查三次,加速了查询数据。

问:为什么索引的数据结构不用二叉树?

答:因为当值依次递增插入时,二叉树会退化成链表,对加快查询没有任何作用。

时间复杂度(代码执行的次数):O(N)

2、红黑树(自平衡二叉查找树)

特点:

  1. 每个节点只能是红色或黑色。
  2. 跟节点必须是黑色。
  3. 红色的节点,它的叶节点只能是黑色。
  4. 从任一节点到其叶子节点的所有路径都包含相同数目的黑色节点。

当数据插入时,红黑树通过旋转和变色来达到平衡。这样就弥补了二叉树退化成链表的尴尬

问:为什么索引的数据结构不用红黑树?

答:因为当值依次递增插入时树的高度会变得特别高。就例如上图查询0007只用3次,那查询70000呢?几乎要用30000次。效率会变得特别低。

时间复杂度为:O(log2N)

3、B树(多路平衡搜索树)

特点:

  1. 一个节点可以有多个元素
  2. 叶节点具有相同的深度,叶节点的指针为空
  3. 所有索引元素不重复
  4. 节点中的数据索引从左到右递增排列

问:为什么索引的数据结构不用B树?

虽然B树相对于红黑树,树的高度降低了,但是随着数据量的增多,树的高度还是会变得很高,效率会变得特别低。而且对范围查找也不方便。

4、B+树

特点:

  1. 非叶子节点不存储data,只存储索引(冗余),可以放多个索引。

  2. 叶子节点包含所有的索引字段

  3. 叶子节点用指针连接,提高区间访问性能(注意是单向指针。)

5、mysql B+树

mysql使用的是B+树,但是不完全是。对原B+树做了一些改造,例如:

  1. 叶子节点改成双向指针,提高范围查询效率。
  2. B树查询性能不稳定,有的直接在根节点就能查到,而有的在叶子节点才能查到。导致查询时快时慢。

6、hash

可以通过对某一值做hash运算,可以快速确定数据存放地址,查询到数据。但是缺点也很明显,不支持范围查询<>。几乎不用

问:为什么innodb表必须有主键?

因为innodb表的索引结构是B+树,而B+树是基于索引来存储数据的。所有的数据全部保存在B+树的叶子节点上。

问:如果没有主键会怎么样?

innodb引擎会查找并选择第一个没有null值的列,作为主键索引。如果没有,则会使用隐藏列作为主键。

问:为什么推荐使用整形自增主键而不用uuid?

优点:

节约空间

插入效率高(由于B+树遵循左小右大,所以自增插入数据总是在最右侧插入。而uuid则不一定,如果页16k已经写满了,那只能把页中的数据向后移,在空位中插入。频繁的移动分页会造成碎片,后续需要使用OPTIMIZE TABLE来进行碎片整理)

问:为什么非主键索引结构叶子节点存储的是主键值?

非主键索引存储主键值,是为了当数据变动时,不需要修改各非主键索引的值,只需修改主键索引叶子结点的数据即可。减少了重复操作,即提高性能。

二、存储引擎的实现

2.1、Innodb页底层结构

分成三个部分

  1. 页头:包含前后页的指针

  2. 页目录:包含数据区(分组)的最小id值,方便通过指针查询到数据

  3. 数据区:用于存放数据,指针依次向下。

为什么要引入页目录?

比如:我要查询id为4的数据,需要从上到下查询4次。把数据区的数据分组,页目录存储每组数据最小的id值。那么我只需要通过目录3,查询2次即可。提高了查询效率。

当一页存满之后,数据会存放到下一页,通过双向指针连接,如图:

当数据越存越多,最终多个页组成了链表。例如:我要查询1000,如果从第1页开始查询,一页一页遍历效率就太慢了(这就是全表扫描)

那怎么办?当然还是用类似页目录的方式了:如图:

到这里就可以大致看出来了,这个结构就是上面说的B+树。每一页即B+树的一个节点

三、主键索引底层结构

问:索引文件对应系统位置在哪?

在mysql目录的data目录下某个数据库名的文件夹下

myisam引擎:包含frm(结构文件)、MYD(data数据文件)、MYI(index索引文件)

innodb引擎包含frm(结构文件)、idb(索引+数据文件)

innodb索引文件和数据文件在一起的(聚集索引)

此处可以看出innodb比myisam引擎少一次磁盘io操作(不需要再去MYD文件取数据),可以说性能好一些。

四、组合索引结构

4.1 SQL关键字:explain

主要关注type字段和row字段:

1. type字段值包括:const、eq_ref、ref、range、index、all

2. row表示扫描的行数、尽量越少越好。关联查询时使用小表驱动大表的方式

4.2 索引失效的情况

1. 使用!=、is null、or关键字
2. 使用like时%加在左边
3. 组合索引没有满足最左匹配原则
4. in的数量太多,也可能导致索引失效
5. where条件后面=左边,也就是对字段进行算数运算或函数操作

总结 

到此这篇关于MySQL原理级别的面试题及答案的文章就介绍到这了,更多相关MySQL原理级别面试题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySql COALESCE函数使用方法代码案例

    MySql COALESCE函数使用方法代码案例

    这篇文章主要介绍了MySql COALESCE函数使用方法代码案例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • MySQL COALESCE 函数使用示例详解

    MySQL COALESCE 函数使用示例详解

    COALESCE是一种SQL函数,用于返回参数列表中第一个非NULL的值,它常用于处理可能存在NULL值的场景,并提供默认值或备用值,这篇文章给大家介绍MySQL COALESCE 函数使用,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • Mysql中的存储过程超详细讲解

    Mysql中的存储过程超详细讲解

    这篇文章主要介绍了Mysql中的存储过程超详细讲解,包括存储过程基本语法,感兴趣的朋友一起看看吧
    2025-04-04
  • MySql按时,天,周,月进行数据统计

    MySql按时,天,周,月进行数据统计

    这篇文章主要介绍了MySql按时,天,周,月进行数据统计,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • 详解mysql中if函数的正确使用姿势

    详解mysql中if函数的正确使用姿势

    这篇文章主要介绍了详解mysql中if函数的正确使用姿势,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Mysql实现将表里的两列值数据互换

    Mysql实现将表里的两列值数据互换

    文章内容为通过将表中数据做临时处理,实现两个订单号互换的方法分享,此方案适用于特定场景下的数据调整需求,旨在提供一种实用的解决思路,供读者参考
    2026-05-05
  • 基于explain性能详细分析

    基于explain性能详细分析

    这篇文章主要介绍了基于explain性能详细分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • 一文带你搞懂MySQL的事务隔离级别

    一文带你搞懂MySQL的事务隔离级别

    这篇文章主要给大家介绍了MySQL事务隔离级别,事务隔离级别分别是读未提交,读已提交,可重复读,串行化,文中有详细的图文介绍,需要的朋友可以参考下
    2023-07-07
  • wamp中mysql安装时能启动重启后无法启动的解决办法

    wamp中mysql安装时能启动重启后无法启动的解决办法

    这篇文章主要介绍了wamp中mysql安装时能启动重启后无法启动的解决办法 ,需要的朋友可以参考下
    2018-08-08
  • 防止mysql重复插入记录的方法

    防止mysql重复插入记录的方法

    这篇文章主要为大家详细介绍了防止mysql重复插入记录的方法,感兴趣的小伙伴们可以参考一下
    2016-05-05

最新评论