mysql数据库的常见面试题

MySQL 常见面试题完全指南

本文档整理了常见的 MySQL 面试题,按从浅到深的顺序讲解,特别适合新手准备面试或系统复习。每个问题都给出:

  • 问题
  • 思路
  • 标准/推荐回答
  • 必要时配合简单示例

你可以:

  • 先只看“问题+简答”,自己在脑子里回答一遍;
  • 然后对照“解析”补充自己的理解;
  • 对不熟的地方回到对应专题文档(如 基本操作、索引、事务 等)复习。

目录

  1. 基础概念与常规操作
  2. 数据类型与表设计
  3. SQL 与 CRUD
  4. 索引相关面试题
  5. 事务与隔离级别
  6. 锁机制
  7. 日志(binlog、redo log、undo log)
  8. 性能优化与慢查询
  9. 设计题与综合题
  10. 杂项与开放题

1. 基础概念与常规操作

1.1 什么是 MySQL?和“数据库”“数据库管理系统”有什么区别?

考点:基础概念、术语区分。

示例回答:

  • 数据库(Database):有结构地存放数据的仓库,可以有很多张表。
  • 数据库管理系统(DBMS):管理数据库的“软件”,负责存储、查询、备份、安全等。
  • MySQL:一个开源的 关系型数据库管理系统(RDBMS),用 SQL 操作数据,数据以表的形式组织。

可以加一句:MySQL 常用于 Web 应用后端,配合 PHP、Java、Python 等语言,是非常常见的数据库选型。


1.2 什么是表?什么是行和列?

考点:能否把“表结构”说清楚。

示例回答:

  • 表(Table):数据库中存放数据的基本结构,可以理解为一张带表头的表格。
  • 列(Column/字段):表中某一“属性”,如学生表里的姓名、年龄、班级。
  • 行(Row/记录):表中的一条具体数据记录,例如“张三,18,高一1班”就是一行。

补充一句:表的结构由列名和数据类型决定,数据则是一行一行的记录。


1.3 MySQL 中常见的约束有哪些?分别有什么作用?

考点:约束类型、作用场景。

关键点:

  • PRIMARY KEY:主键,唯一标识一行,不能重复、不能为 NULL。
  • UNIQUE:唯一约束,列值不能重复(可为 NULL)。
  • NOT NULL:非空,列值必须有,不允许 NULL。
  • DEFAULT:默认值,插入时未指定该列就用默认值。
  • CHECK(8.0.16+):检查约束,列值必须满足条件,如年龄 0~150。
  • FOREIGN KEY:外键,保证该列的取值必须在另一张表的主键或唯一键中存在。

可以举例学生-班级、订单-用户来说明外键约束的作用。


1.4 如何查看当前有哪些数据库?如何选择要使用的数据库?

考点:基本命令是否熟练。

关键命令:

  • 查看所有数据库:
SHOW DATABASES;
  • 选择(切换)数据库:
USE 库名;
  • 查看当前正在使用的数据库:
SELECT DATABASE();

1.5 MySQL 中如何查看某个表的结构?如何查看当前库下所有表?

命令:

  • 查看所有表:
SHOW TABLES;
  • 查看表结构:
DESC 表名;
-- 或
DESCRIBE 表名;

2. 数据类型与表设计

2.1 MySQL 中常见的数据类型有哪些?如何选择?

考点:能否说出主流类型并举例。

简要回答:

  • 数值:
    • INT / BIGINT:整数,如 id、数量。
    • DECIMAL(M,D):精确小数,如金额、分数。
    • FLOAT / DOUBLE:近似小数,如比例、统计值。
  • 字符串:
    • VARCHAR(n):可变长字符串,适合大部分文本,如姓名、标题。
    • CHAR(n):定长字符串,如固定长度编码。
    • TEXT / LONGTEXT:长文本,如文章内容。
  • 日期时间:
    • DATE:日期。
    • TIME:时间。
    • DATETIME / TIMESTAMP:日期 + 时间。

可以补一句:金额一般用 DECIMAL,而不是 FLOAT/DOUBLE,以避免精度问题。


2.2 VARCHAR 和 CHAR 有什么区别?什么时候用 VARCHAR,什么时候用 CHAR?

考点:存储与性能差异。

回答要点:

  • CHAR(n):定长字符串:
    • 不足长度时用空格填充;
    • 适合长度固定、变化不大的字段,如性别(CHAR(1))、国家代码、固定长度的编码。
  • VARCHAR(n):变长字符串:
    • 按实际长度存储,多一个长度字节;
    • 适合大部分长度不固定的文本,如姓名、地址、标题。

一般建议:绝大多数情况使用 VARCHAR,只有真的是定长字段(且长度不大)才考虑 CHAR。


2.3 为什么建议每张表都有一个自增主键 id?

考点:主键设计意识。

回答示例:

  • 自增整数主键(INT/BIGINT)简单、稳定,便于:
    • 在程序中做唯一标识;
    • 做外键引用;
    • 做聚簇索引时减少页分裂(顺序插入)。
  • 业务字段(如身份证号、手机号)做主键:
    • 可能会变化;
    • 字段较长作为聚簇索引会影响性能和存储。

可以提到:逻辑上“主键应该稳定、不随业务变化”,自增 id 是典型实现。


3. SQL 与 CRUD

3.1 写出一条插入语句、一条更新语句、一条删除语句和一条简单查询语句

考点:基础 CRUD 是否熟悉。

示例:

-- 插入
INSERT INTO students (name, gender, age, class_name)
VALUES ('张三', '男', 18, '高一1班');

-- 更新
UPDATE students
SET age = 19
WHERE id = 1;

-- 删除
DELETE FROM students
WHERE id = 1;

-- 查询
SELECT id, name, age
FROM students
WHERE class_name = '高一1班';

面试时可以顺便强调:UPDATE/DELETE 一定要加 WHERE,否则会改/删全表。


3.2 WHERE 和 HAVING 有什么区别?

考点:分组与过滤的执行顺序。

回答要点:

  • WHERE
    • 分组(GROUP BY)之前执行;
    • 用来过滤“行”,不允许使用聚合函数(如 COUNT、AVG 等)。
  • HAVING
    • 分组(GROUP BY)之后执行;
    • 用来过滤“组”,常用聚合函数(如 HAVING COUNT(*) > 2)。

可以举例:

-- 先用 WHERE 过滤,只统计高一1班
SELECT class_name, COUNT(*) AS 人数
FROM students
WHERE class_name = '高一1班'
GROUP BY class_name
HAVING COUNT(*) > 2;  -- 再按组的人数筛选

3.3 INNER JOIN、LEFT JOIN、RIGHT JOIN 的区别?

考点:连接类型、结果集差异。

回答要点:

  • INNER JOIN(内连接)
    • 只保留左右表都能匹配上的行;
    • 不匹配的行不会出现在结果中。
  • LEFT JOIN(左连接)
    • 以左表为基准,左表所有行都保留;
    • 右表匹配上的行会拼上,匹配不上时右表列为 NULL。
  • RIGHT JOIN(右连接)
    • 以右表为基准,右表所有行都保留;
    • 左表匹配不上时左表列为 NULL;
    • 一般可以通过调整书写顺序 + LEFT JOIN 代替。

建议配一个学生-班级的小例子来解释。


4. 索引相关面试题

4.1 什么是索引?有什么优点和缺点?

考点:索引本质、利弊。

回答要点:

  • 索引是建立在表的某些列上的数据结构(一般是 B+ 树),用来加快数据的查找和排序
  • 优点
    • 大幅提高查询速度,尤其是 WHERE、ORDER BY、GROUP BY、JOIN 中使用的列。
    • 降低 I/O,减少全表扫描。
  • 缺点
    • 需要额外的存储空间;
    • 写操作(INSERT/UPDATE/DELETE)需要维护索引结构,写入速度会变慢;
    • 过多或设计不合理的索引会适得其反。

4.2 MySQL 中有哪些类型的索引?

考点:概念区分。

回答要点:

  • 按用途:
    • 主键索引(PRIMARY KEY):主键列自动创建,唯一且非空。
    • 唯一索引(UNIQUE):列值不能重复。
    • 普通索引(INDEX/KEY):只加速查询,不限制列值。
    • 全文索引(FULLTEXT):用于文本搜索(如匹配单词),InnoDB 从 5.6 开始支持。
  • 按列数:
    • 单列索引:只包含一列。
    • 复合索引(联合索引):包含多列,如 INDEX (col1, col2)。

可补一句:大多数情况下我们说“建索引”就是建 B+ 树索引,具体实现取决于存储引擎(如 InnoDB)。


4.3 什么是联合(复合)索引?什么是“最左前缀原则”?

考点:复合索引使用规则。

回答要点:

  • 复合索引:在多列上一起建立一个索引,例如 INDEX (class_name, age)。
  • 最左前缀原则
    • 复合索引会从最左边的列开始起作用;
    • 能用到索引的条件必须包含索引的前缀列
    • (class_name, age) 可加速:
      • WHERE class_name = ?
      • WHERE class_name = ? AND age = ?
    • 但对 WHERE age = ? 单独使用时往往用不上这个联合索引。

面试时可以画一小段:

想象索引是按 class_name 再按 age 排序的一本“电话簿”,只写 age 就没法利用前面的顺序了。


4.4 什么情况下适合建索引?什么情况下不适合建索引?

考点:索引设计意识。

适合建索引:

  • 经常出现在 WHERE 条件ORDER BYGROUP BYJOIN 条件中的列。
  • 区分度较高的列(不同值较多,如用户 id、订单号)。
  • 外键列(用于关联查询)。

不适合建索引:

  • 频繁更新的列(特别是值变化很大又经常修改的列),索引维护成本高。
  • 区分度很低的列(如性别、布尔值),一般不单独建索引。
  • 表非常小(几百行),全表扫描也很快。
  • 仅参与计算但不参与筛选/排序的列。

可以总结一句:多查少写的列更适合建索引;少查多写的列尽量少建索引。


4.5 覆盖索引是什么?

考点:优化方向。

简要回答:

  • 覆盖索引:查询所需的列都在索引里,不需要回表(再访问数据页),直接从索引就能返回结果。
  • 例如索引 (name, age),查询 SELECT name, age FROM students WHERE name = '张三'; 时,如果条件和返回列都在这个索引中,就可以只访问索引,减少 I/O。

可以补一句:覆盖索引能显著减少磁盘访问,是常见的优化手段之一。


5. 事务与隔离级别

5.1 什么是事务(Transaction)?有哪四大特性(ACID)?

考点:事务基础。

回答要点:

  • 事务:一组要么全部成功、要么全部失败的操作,是数据库保证数据一致性的重要机制。
  • ACID:
    • A(Atomicity,原子性):事务中的操作要么全部成功,要么全部失败回滚。
    • C(Consistency,一致性):事务前后,数据库从一种一致状态转变为另一种一致状态。
    • I(Isolation,隔离性):并发事务互不影响,看起来像顺序执行一样。
    • D(Durability,持久性):事务提交后,对数据的修改是持久的,即使系统故障也不会丢失(依赖日志、落盘机制)。

5.2 MySQL 有哪些事务隔离级别?各自会出现哪些并发问题?

考点:四个隔离级别、常见并发现象。

隔离级别(从低到高):

  1. READ UNCOMMITTED(读未提交)
    • 可能出现:脏读、不可重复读、幻读
  2. READ COMMITTED(读已提交)
    • 解决脏读(只能读到已提交的数据)。
    • 仍可能出现:不可重复读、幻读
  3. REPEATABLE READ(可重复读) —— MySQL InnoDB 默认
    • 在同一事务中,多次读取同一行结果一致(无不可重复读)。
    • 在 MySQL 的 MVCC + 间隙锁机制下,通常也能避免大部分幻读问题。
  4. SERIALIZABLE(可串行化)
    • 最高级别,所有事务串行执行,避免所有并发问题,但性能最差。

常见并发问题简单解释:

  • 脏读:读到了“别的事务尚未提交”的数据。
  • 不可重复读:同一事务里,两次读到同一行的结果不同(因为其他事务更新并提交了该行)。
  • 幻读:同一事务里,两次统计/查询满足条件的行数不一样(别的事务插入或删除了一些符合条件的行)。

5.3 InnoDB 与 MyISAM 的区别?

考点:存储引擎差异。

要点:

  • InnoDB:
    • 支持事务行级锁外键
    • 默认存储引擎,可靠性好,适合大部分 OLTP 场景。
  • MyISAM:
    • 不支持事务、外键,锁粒度是表级锁
    • 插入/查询速度在某些场景下较快,但安全性和并发能力较差;
    • 在新项目中已较少使用。

可以总结:现在大多数情况下我们都选 InnoDB。


6. 锁机制

6.1 行锁和表锁有什么区别?MySQL 里分别如何实现?

考点:锁粒度、性能影响。

回答要点:

  • 表锁
    • 对整张表加锁;
    • 并发度低,但开销小;
    • MyISAM 主要使用表锁。
  • 行锁
    • 只锁某一行或某几行;
    • 并发度高,但实现更复杂,开销相对大;
    • InnoDB 支持行级锁(也会在必要时退化为间隙锁/表锁)。

可以提到:InnoDB 通过索引实现行级锁,对没有索引的查询可能退化为锁全表。


6.2 什么是死锁?如何避免?

考点:并发控制意识。

简要回答:

  • 死锁:两个(或多个)事务互相持有对方需要的锁,并都在等待对方释放,导致都无法继续执行。
  • 避免方式:
    • 访问表和行的顺序尽量一致,减少交叉锁;
    • 尽量保持事务简短,避免长事务;
    • 尽早释放锁;
    • 合理设计索引,减少锁范围。

MySQL InnoDB 会自动检测死锁并回滚其中一个事务,需要在应用层做好重试逻辑。


7. 日志(binlog、redo log、undo log)

7.1 MySQL 中有哪些重要日志?作用是什么?

考点:日志类型及用途。

主要日志:

  • 二进制日志(binlog)
    • 记录对数据库进行的“写操作”的逻辑日志(如 INSERT、UPDATE、DELETE);
    • 用于主从复制、数据恢复(基于 point-in-time 恢复)。
  • 重做日志(redo log) —— InnoDB 专有:
    • 记录页的物理修改,用于崩溃恢复(保证事务持久性);
    • 提高写入性能(先写日志,再异步刷盘)。
  • 回滚日志(undo log)
    • 记录旧数据,用于事务回滚和实现 MVCC(多版本并发控制)。
  • 错误日志(error log):记录启动、关闭、运行错误信息。
  • 慢查询日志(slow query log):记录执行时间超过阈值的 SQL,便于优化。

面试中常被问的是 binlog、redo log、undo log 三者的区别与作用。


8. 性能优化与慢查询

8.1 如何定位并优化慢查询?

考点:排查思路。

典型回答结构:

  1. 开启慢查询日志
    • 记录执行时间超过某个阈值的 SQL(如 long_query_time = 1s)。
  2. 使用 EXPLAIN 分析执行计划
    • 查看是否走了索引(key 列);
    • type 是否为 ALL(全表扫描);
    • rows 预估扫描行数是否太大。
  3. 检查索引设计
    • 为 WHERE、JOIN、ORDER BY、GROUP BY 中的高频列建合适的索引;
    • 避免函数操作导致索引失效;
    • 合理使用复合索引(遵循最左前缀)。
  4. 优化 SQL 写法
    • 减少 SELECT *,只查必要列;
    • 避免不必要的子查询、嵌套;
    • 对大表分页、分批处理。
  5. 必要时考虑表结构与系统层面优化
    • 规范化/反规范化;
    • 分表分库、读写分离等(进阶)。

8.2 EXPLAIN 输出中哪些字段比较重要?

考点:能读懂基础执行计划。

回答要点:

  • 重要字段:
    • type:访问类型,常见值有 ALL、index、range、ref、eq_ref、const 等。
    • 从好到坏大致:system > const > eq_ref > ref > range > index > ALL
    • ALL 表示全表扫描。
    • key:实际用到的索引名,为 NULL 表示没用索引。
    • rows:预估扫描的行数,越少越好。
    • Extra:额外信息,常见如 Using where / Using index / Using filesort 等。

可以简单解释:关注是否走索引(key)、是否全表扫描(type=ALL)、扫描行数是否太大。


9. 设计题与综合题

9.1 如何设计一个学生-课程-成绩的表结构?

考点:三表设计、一对多、多对多。

推荐答案思路:

  1. 学生表 students
CREATE TABLE students (
    id          INT PRIMARY KEY AUTO_INCREMENT,
    name        VARCHAR(50) NOT NULL,
    gender      CHAR(1),
    class_name  VARCHAR(20)
);
  1. 课程表 courses
CREATE TABLE courses (
    id      INT PRIMARY KEY AUTO_INCREMENT,
    name    VARCHAR(50) NOT NULL
);
  1. 选课/成绩表 student_course_scores(中间表,多对多关系 + 成绩):
CREATE TABLE student_course_scores (
    id          INT PRIMARY KEY AUTO_INCREMENT,
    student_id  INT NOT NULL,
    course_id   INT NOT NULL,
    score       DECIMAL(5,2),
    UNIQUE KEY uk_stu_course (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES students(id),
    FOREIGN KEY (course_id) REFERENCES courses(id)
);

说明:

  • 学生和课程是多对多,用中间表表示;
  • UNIQUE (student_id, course_id) 保证一个学生一门课只有一条记录;
  • 外键保证 student_id / course_id 的合法性(视项目是否实际启用外键)。

9.2 假如有一张访问日志表非常大(上亿条),你会如何优化它的查询?

考点:大表优化思路。

可回答方向:

  • 合理建索引
    • 针对常用查询条件(如 user_id、url、时间范围)建立合适的单列或复合索引;
    • 避免在索引列上用函数或不等值导致索引失效。
  • 分区/分表(进阶):
    • 按时间(按天、按月)分区或分表,减少单个查询扫描数据量;
    • 老数据归档到历史表。
  • 限制查询范围
    • 前端分页 + 限制最大可查时间区间;
    • 避免一次性扫全历史。
  • 使用缓存
    • 对热点统计结果做缓存(例如 Redis),减少重复查询。

10. 杂项与开放题

10.1 MySQL 中如何防止 SQL 注入?

考点:安全意识。

回答要点:

  • 不要直接字符串拼接 SQL;
  • 使用预编译语句(Prepared Statement) 或 ORM 框架提供的参数绑定;
  • 对输入做必要的校验、长度限制;
  • 严格控制数据库用户权限(只给必要权限)。

10.2 有哪些常用的 MySQL 优化经验?

可以罗列几个关键点:

  1. SQL 层面:
    • 避免 SELECT *,只查必要列;
    • WHERE 条件写在索引列上,避免函数包裹索引列;
    • 减少子查询嵌套,适当改用 JOIN;
    • 用 LIMIT 做分页和限制结果大小。
  2. 索引层面:
    • 为高频查询、排序、分组列建合适索引;
    • 合理设计复合索引(最左前缀);
    • 清理长期不用、重复或低效索引。
  3. 表设计:
    • 字段类型选择合理,避免过度宽表;
    • 每表有主键,自增整数主键常见;
    • 必要时归档历史数据。
  4. 运维层面:
    • 打开慢查询日志,定期分析;
    • 合理设置缓存、连接数等参数。

小结与面试建议

  • 概念题:多用“先下定义,再举例子,再说优缺点”的结构回答;
  • 操作题:脑中有 SQL 语法模板,尽量写出完整语句;
  • 设计题:先讲清关系(一对多、多对多),再给出表结构;
  • 优化题:从 SQL → 索引 → 表设计 → 系统/架构层面,分层次回答。

建议你:

  • 先通读本文,把不懂的地方在前面的专题文档中查一遍;
  • 自己拿纸写几遍索引、事务、Join 类型、隔离级别等核心知识点;
  • 在本机 MySQL 上把常用命令(CRUD、建表、索引、事务、备份恢复)实操 1~2 遍,效果会更好。**

发表评论