基础与引擎 - MySQL 面试题及答案
2025/12/19大约 6 分钟
返回MySQL 面试题索引 第 1/4 章
1.说一说三大范式
- 「第一范式」:[数据库]「原子性」,不可再分,并且是单一职责
- 「第二范式」:「建立在第一范式的基础上」,第二范式要求数据库表中的每个实例或行必须**「可以被惟一地区分」**。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主键
- 「第三范式」:「建立在第一,第二范式的基础上」,确保每列都和主键列直接相关,而不是间接相关不存在其他表的非主键信息
但是在我们的日常开发当中,「并不是所有的表一定要满足三大范式」,有时候冗余几个字段可以少关联几张表,带来的查询效率的提升有可能是质变的
2.MyISAM 与 InnoDB 的区别是什么?

- 「InnoDB支持事务,MyISAM不支持」。
- 「InnoDB 支持外键,而 MyISAM 不支持」。
- 「InnoDB是聚集索引」,使用B+Tree作为索引结构,数据文件是和索引绑在一起的,必须要有主键。「MyISAM是非聚集索引」,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
- 「InnoDB 不保存表的具体行数」。「MyISAM 用一个变量保存了整个表的行数」。
- 5.Innodb 有 「redolog」 日志文件,MyISAM 没有
- 6.「Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI」
- Innodb:frm是表定义文件,ibd是数据文件
- Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
- 「InnoDB 支持表、行锁,而 MyISAM 支持表级锁」
- 8、「InnoDB 必须有唯一索引(主键)」,如果没有指定的话 InnoDB 会自己生成一个隐藏列Row_id来充当默认主键,「MyISAM 可以没有」
3.为什么推荐使用自增 id 作为主键?

- 1.普通索引的 B+ 树上存放的是主键索引的值,如果该值较大,会**「导致普通索引的存储空间较大」**
- 2.使用自增 id 做主键索引新插入数据只要放在该页的最尾端就可以,直接**「按照顺序插入」**,不用刻意维护
- 3.页分裂容易维护,当插入数据的当前页快满时,会发生页分裂的现象,如果主键索引不为自增 id,那么数据就可能从页的中间插入,页的数据会频繁的变动,「导致页分裂维护成本较高」
4.一条查询语句是怎么执行的?

- 1.通过连接器跟客户端**「建立连接」**
- 2.通过查询**「缓存查询」**之前是否有查询过该 sql
- 有则直接返回结果
- 没有则执行第三步
- 3.通过分析器**「分析该 sql 的语义」**是否正确,包括格式,表等等
- 4.通过优化器**「优化该语句」**,比如选择索引,join 表的连接顺序
- 5.「验证权限」,验证是否有该表的查询权限
- 没有则返回无权限的错误
- 有则执行第六步
- 6.通过执行器调用存储引擎执行该 sql,然后返回**「执行结果」**
5.使用 Innodb 的情况下,一条更新语句是怎么执行的?
用以下语句来举例,c 字段无索引,id 为主键索引
update T set c=c+1 where id=2;
复制
- 1.执行器先找引擎取 id=2 这一行。id 是主键,引擎直接用树搜索找到这一行
- 如果 id=2 这一行所在的数据页本来就**「在内存中」,就「直接返回」**给执行器
- 「不在内存」中,需要先从磁盘「读入内存」,然后再**「返回」**
- 2.执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口**「写入这行新数据」**
- 3.引擎将这行新数据更新到内存中,同时将这个更新操作**「记录到 redo log 里面」**,此时 redo log 处于 「prepare」 状态。然后告知执行器执行完成了,随时可以提交事务
- 4.执行器**「生成这个操作的 binlog」**,并把 binlog 「写入磁盘」
- 5.执行器调用引擎的**「提交事务」接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,「更新完成」**
6.Innodb 事务为什么要两阶段提交?
- 先写 redolog 后写binlog。假设在 redolog 写完,binlog 还没有写完的时候,MySQL 进程异常重启,这时候 binlog 里面就没有记录这个语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 「binlog 丢失」,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
- 先写 binlog 后写 redolog。如果在 binlog 写完之后 crash,由于 redolog 还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是 binlog 里面已经记录了“把c从0改成1”这个日志。所以,在之后用 binlog 来恢复的时候就**「多了一个事务出来」**,恢复出来的这一行 c 的值就是 1,与原库的值不同。
可以看到,「如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致」。
最近建一些几十个工作内推群,各大城市都有,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。 欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。
