mysql面试题整理

1.mysql mvcc 机制

在 MySQL 面试中,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一个高频考点,主要考察候选人对事务隔离级别和并发控制机制的理解。以下是针对 MVCC 的核心知识点总结:


1. mysql MVCC 是什么?

  • 定义:MVCC 是一种通过维护数据的多个版本来实现并发控制的技术,目的是在高并发场景下减少锁的竞争,提高读操作的性能。
  • 解决的问题
    • 避免读写操作互相阻塞(读不阻塞写,写不阻塞读)。
    • 实现事务的隔离性(如 REPEATABLE READREAD COMMITTED 隔离级别)。

2. MVCC 的实现原理

核心机制
  1. 隐藏字段
    • DB_TRX_ID:记录最后一次修改该数据的事务 ID。
    • DB_ROLL_PTR:指向 Undo Log 中旧版本数据的指针,形成数据的版本链。
    • DB_ROW_ID:隐含的自增行 ID(如果表没有主键)。
  2. Undo Log
    • 存储数据的历史版本,用于事务回滚和 MVCC 的版本链访问。
    • 每次更新操作会生成一个 Undo Log 记录,并通过 DB_ROLL_PTR 连接成链表。
  3. Read View(读视图)
    • 事务在快照读 (普通 SELECT)时生成的"数据可见性"快照。
    • 包含以下关键信息:
      • trx_ids:当前活跃(未提交)的事务 ID 列表。
      • min_trx_id:最小活跃事务 ID。
      • max_trx_id:下一个即将分配的事务 ID。
      • creator_trx_id:创建该 Read View 的事务 ID。

3. 数据可见性规则

通过 Read View 判断某行数据的某个版本是否对当前事务可见:

  1. 如果数据版本的 DB_TRX_ID < min_trx_id:说明该版本在 Read View 创建前已提交,可见
  2. 如果 DB_TRX_ID > max_trx_id:说明该版本在 Read View 创建后生成,不可见
  3. 如果 min_trx_id ≤ DB_TRX_ID ≤ max_trx_id
    • DB_TRX_IDtrx_ids 列表中,说明事务未提交,不可见
    • 若不在列表中,说明事务已提交,可见
  4. 若当前事务自身修改的数据(DB_TRX_ID = creator_trx_id),可见。

如果不可见,则通过 DB_ROLL_PTR 查找 Undo Log 中的旧版本,重复上述判断。


4. 不同隔离级别的实现

  • READ COMMITTED(读已提交)

    • 每次执行 SELECT 时生成新的 Read View,能看到其他事务已提交的修改。
  • REPEATABLE READ(可重复读)

    • 仅在第一次 SELECT 时生成 Read View,后续读取沿用该视图,保证多次读取的一致性。
    • 通过 MVCC + 间隙锁(Next-Key Locks)解决幻读问题。

    4.1 进一步解释

    首先,我们来看一下标准的SQL隔离级别和它们解决的问题:

    1. 脏读(Dirty Read):一个事务读取了另一个未提交事务修改的数据。
    2. 不可重复读(Non-repeatable Read):一个事务内多次读取同一数据,但在读取过程中,另一个事务修改并提交了数据,导致第一个事务两次读取的数据不一致。
    3. 幻读(Phantom Read):一个事务在多次查询过程中,由于其他事务插入或删除了数据,导致每次查询的结果集不同。

    不同隔离级别对上述问题的解决情况:

    • READ UNCOMMITTED: 可能发生脏读、不可重复读和幻读。
    • READ COMMITTED: 防止脏读,但可能发生不可重复读和幻读。
    • REPEATABLE READ: 防止脏读和不可重复读,但可能发生幻读(但在MySQL的InnoDB引擎中,通过多版本并发控制MVCC和间隙锁,在REPEATABLE READ级别下也可以防止幻读)。
    • SERIALIZABLE: 防止所有问题,但并发性能最低,因为它通过强制事务串行执行来实现。

5. 面试常见问题

Q1:MVCC 如何避免脏读、不可重复读?
  • 脏读:Read View 过滤未提交的事务版本。
  • 不可重复读:在 REPEATABLE READ 下,Read View 在事务期间保持不变,确保多次读取一致性。
Q2:MVCC 能完全解决幻读吗?
  • 快照读(普通 SELECT)通过 MVCC 避免幻读。
  • 当前读 (如 SELECT FOR UPDATE)可能发生幻读,需依赖间隙锁(Next-Key Locks)解决。
Q3:Undo Log 何时删除?
  • 当没有事务需要访问旧版本数据时(即所有 Read View 都不再依赖该 Undo Log),由后台线程清理。

5.1 数据库三范式
5.2 mysql 数据库 explain

更准确的排序和理解如下:

访问类型 性能 详细说明
system 最优 表中只有一行数据(等于系统表),是 const 的特例。
const 极优 通过主键或唯一索引的一次扫描,最多只返回一条记录。速度快如常量。
eq_ref 极优 在联表查询时,使用主键或唯一索引进行关联。对于来自前表的每一行,从本表中只读取一行。
ref 使用普通索引(非唯一)进行查找,可能返回多条匹配的行。
fulltext 特殊 使用全文索引。性能高度依赖于匹配的相关度和数据量,很难简单排序。通常用于文本搜索,和常规查询可比性不强。
ref_or_null 类似 ref,但附加了对 NULL 值的搜索。
unique_subquery 在子查询中,将 IN 查询转换为高效的 EXISTS 子查询,使用主键。
index_subquery 类似 unique_subquery,但使用的是普通索引。
range 使用索引检索给定范围的行(如 BETWEEN, >, IN)。关键是不再是全索引扫描。
index_merge 不稳定 这是原列表中最需要调整的地方。 它表示使用了索引合并优化(使用多个索引)。它的性能可能很好,也可能很差 ,取决于合并哪些索引以及需要扫描的数据量。有时它甚至不如单个范围的 range 扫描。不应简单地认为它比 range 好。
index 全索引扫描。虽然不读数据行,只读索引,但如果索引很大,速度依然很慢。
ALL 最差 全表扫描。没有使用索引,性能最差,必须优化。

例如从基本使⽤使⽤的⾓度来讲:

主键索引: InnoDB 主键是默认的索引,数据列不允许重复,不允许为 NULL,⼀个表只能有⼀个

主键。

唯⼀索引: 数据列不允许重复,允许为 NULL 值,⼀个表允许多个列创建唯⼀索引。

普通索引: 基本的索引类型,没有唯⼀性的限制,允许为 NULL 值。

组合索引:多列值组成⼀个索引,⽤于组合搜索,效率⼤于索引合并。

5.3 索引下推

它的核心思想是:将一部分数据过滤工作从MySQL服务器层"下推"到存储引擎层去执行。

复制代码
没有索引下推时,是如何工作的?
让我们通过一个例子来理解。假设我们有一张 users 表和一个索引 INDEX (name, age):

sql
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    city VARCHAR(50),
    KEY idx_name_age (name, age)
);
执行以下查询:

sql
SELECT * FROM users 
WHERE name LIKE '张%' 
AND age = 20;
存储引擎:

使用联合索引 idx_name_age,找到所有 name 以 "张" 开头的记录。

因为索引中包含 name 和 age 字段,但它只根据 name 这一部分来定位数据页。

将所有这些匹配 name LIKE '张%' 的完整数据行(即使是使用索引,也需要回表读取完整行数据),返回给MySQL的服务器层。

服务器层:

接收到存储引擎返回的所有 name LIKE '张%' 的行。

然后由服务器层来执行第二条条件 age = 20 的过滤。

问题所在:存储引擎返回了大量 name 符合条件但 age 不等于20的行,这些不必要的行在服务器层被过滤掉了,导致了额外的I/O和网络传输(在服务器层和存储引擎层之间)。

开启索引下推后,是如何工作的?
同样是这个查询和索引 INDEX (name, age):

存储引擎:

同样使用索引 idx_name_age,找到所有 name 以 "张" 开头的记录。

关键区别来了:由于 age 字段也在同一个索引中,存储引擎会就地检查这些索引记录中的 age 字段是否等于20。

只有同时满足 name LIKE '张%' 和 age = 20 的索引项,存储引擎才会去回表读取完整的行数据,然后返回给服务器层。

服务器层:

接收到的行已经是完全符合 name LIKE '张%' AND age = 20 的结果集了。

服务器层直接使用这些数据,无需再做额外的过滤。
5.4 mysql 优先级顺序

优先级顺序表

优先级 运算符 描述
1 () 括号(强制改变优先级)
2 - + ~ ! 一元运算符:负号、正号、位非、逻辑非
3 ^ 位异或
4 * / % DIV 乘、除、取模、整除
5 + - 加、减
6 << >> 位左移、位右移
7 & 位与
8 ` ` 位或
9 = <=> > < >= <= <> != LIKE REGEXP IN IS BETWEEN CASE 比较运算符
10 NOT 逻辑非
11 AND && 逻辑与
12 XOR 逻辑异或
13 OR ` `
14 := 赋值运算符

重要说明

括号最高优先级

sql

复制代码
-- 括号强制改变运算顺序
SELECT (1 + 2) * 3;  -- 结果为 9
SELECT 1 + 2 * 3;    -- 结果为 7

算术运算符优先级

sql

复制代码
-- 先乘除后加减
SELECT 2 + 3 * 4;      -- 14,不是 20
SELECT 10 / 2 + 3;     -- 8,不是 2
SELECT 10 % 3 * 2;     -- 2,不是 10%6=4

逻辑运算符优先级

sql

复制代码
-- AND 优先级高于 OR
SELECT * FROM users 
WHERE age > 18 OR status = 'active' AND deleted = 0;
-- 等价于:age > 18 OR (status = 'active' AND deleted = 0)

-- 使用括号明确意图
SELECT * FROM users 
WHERE (age > 18 OR status = 'active') AND deleted = 0;

比较运算符优先级

sql

复制代码
-- 比较运算符优先级低于算术运算符
SELECT * FROM products 
WHERE price * 1.1 > 100;  -- 先计算 price*1.1,再比较

特殊注意事项

  1. BETWEEN 的优先级

    sql

    复制代码
    -- BETWEEN 优先级较低
    SELECT * FROM table 
    WHERE id = 1 OR id BETWEEN 5 AND 10;
    -- 等价于:id = 1 OR (id >= 5 AND id <= 10)
  2. IN 运算符

    sql

    复制代码
    -- IN 优先级高于 OR
    SELECT * FROM users 
    WHERE status = 'active' OR id IN (1, 2, 3);
    -- 等价于:status = 'active' OR (id IN (1, 2, 3))
  3. IS NULL 运算符

    sql

    复制代码
    -- IS NULL 优先级
    SELECT * FROM users 
    WHERE name IS NULL OR name = '';

5.6 集群架构设计

6. 总结

  • 优点:提高并发性能,读写互不阻塞。
  • 缺点:需要维护多版本数据,增加存储和 CPU 开销。
  • 适用场景:读多写少的高并发系统(如电商、社交应用)。

掌握 MVCC 的核心机制和与隔离级别的关系,能帮助你在面试中清晰阐述其工作原理和应用场景。

MySQL 数据库的备份方式多样,根据业务需求、数据量、停机时间容忍度等因素,可选择合适的备份策略。以下是常见的备份方式及其特点:

2.mysql 备份


一、逻辑备份

1. mysqldump
  • 原理:生成 SQL 语句文件(CREATE TABLE + INSERT 语句)。

  • 优点

    • 跨版本兼容(如从 MySQL 5.7 迁移到 8.0)。
    • 可选择性备份表或数据库。
    • 支持压缩输出(--compress)。
  • 缺点

    • 大数据量时备份和恢复较慢。
    • 备份时可能锁表(默认使用--lock-tables)。
  • 命令示例

    bash

    复制

    复制代码
    mysqldump -u [user] -p [database] > backup.sql
2. mysqlpump(MySQL 5.7+)
  • 原理 :类似 mysqldump,但支持并行导出。
  • 优点
    • 多线程加速导出(--default-parallelism=N)。
    • 支持压缩(--compress-output)。
  • 缺点
    • 不保证数据一致性(需配合事务或 FTWRL 锁)。
    • 部分功能限制(如无法导出事件)。
3. SELECT ... INTO OUTFILE
  • 原理:将单表数据导出为 CSV/文本文件。
  • 优点
    • 轻量级导出特定表数据。
    • 可与其他工具(如 LOAD DATA INFILE)结合使用。
  • 缺点
    • 仅备份数据,不备份表结构。
    • 需要手动处理锁。

二、物理备份

1. 直接复制数据文件
  • 原理 :直接拷贝 MySQL 数据目录(/var/lib/mysql)。
  • 优点
    • 备份速度快(适合大数据库)。
    • 支持热备份(需保证数据一致性)。
  • 缺点
    • 需停机或使用锁(FLUSH TABLES WITH READ LOCK)。
    • 依赖存储引擎(如 InnoDB 需同时备份事务日志)。
2. Percona XtraBackup
  • 原理:物理备份工具,支持 InnoDB 热备份。

  • 优点

    • 在线备份(不锁表)。
    • 支持增量备份和压缩。
    • 快速恢复(直接替换数据文件)。
  • 命令示例

    bash

    复制

    复制代码
    xtrabackup --backup --user=[user] --password=[pass] --target-dir=/backup/

三、增量备份

1. 基于二进制日志(Binlog)
  • 原理
    • 先做全量备份,之后定期备份 Binlog 文件。
    • 恢复时,通过全量备份 + Binlog 重放恢复到指定时间点。
  • 优点
    • 节省存储空间。
    • 支持时间点恢复(PITR)。
  • 配置要求
    • 启用 log_binserver_id
    • 定期备份 Binlog 并清理过期文件。
2. Percona XtraBackup 增量备份
  • 原理:基于全量备份,仅备份自上次备份后修改的数据页。
  • 优点
    • 减少备份时间和存储占用。
    • 支持合并增量备份到全量备份。

四、主从复制

  • 原理:通过主从架构实时同步数据。
  • 优点
    • 从库可视为实时备份。
    • 支持读写分离和故障切换。
  • 缺点
    • 需额外硬件资源。
    • 主从延迟可能导致数据不一致。

五、云服务备份

  • AWS RDS/Aurora:自动每日备份 + Binlog 保留。
  • 阿里云/Azure:支持手动快照和自动策略。
  • 优点
    • 自动化管理,无需手动维护。
    • 集成存储和恢复功能。

六、快照备份

  • 原理:利用存储层快照(如 LVM、ZFS、云硬盘快照)。
  • 优点
    • 瞬时完成(秒级)。
    • 适合大规模数据备份。
  • 条件
    • 需确保快照时数据库处于一致性状态(如 FLUSH TABLES WITH READ LOCK)。

七、备份策略建议

  1. 全量 + 增量组合:每周全量备份 + 每日增量备份。
  2. 验证备份:定期测试备份文件可恢复性。
  3. 异地存储:备份文件存放到不同地理位置或云存储。
  4. 加密与压缩:保护敏感数据,减少存储成本。

8 mysql 数据库 目录

etc/my.cnf 改了以后需要重启一下服务器


七、工具对比与选型建议

工具/方案 适用场景 优点 缺点
mysqldump 小库、单表备份,跨版本迁移 简单灵活,无需额外依赖 大库备份慢,锁表风险
XtraBackup 大库热备份,生产环境主流方案 快速,支持增量,开源免费 需学习配置
MySQL Shell MySQL 8.0+ 环境,并行导出 高性能,集成度高 仅限新版 MySQL
云服务内置备份 云托管数据库 自动化,无需运维 依赖云厂商,成本较高

在 MySQL 面试中,优化参数是高频考点。以下是一些面试中常被问及的优化参数及其核心解释,帮助你在面试中快速组织回答:


3.mysql 内存参数优化

1. 内存相关参数

innodb_buffer_pool_size
  • 作用 :InnoDB 存储引擎的核心缓存池,缓存数据和索引。直接影响读性能
  • 推荐值 :通常设置为物理内存的 50%~80%(例如 64G 服务器可设为 40G~50G)。
  • 面试追问
    • 如何确定当前值是否合理?
      通过监控 Innodb_buffer_pool_read_requests(缓存命中次数)和 Innodb_buffer_pool_reads(直接读磁盘次数),计算缓存命中率:
      命中率 = 1 - (reads / read_requests),理想值应 > 99%。
key_buffer_size
  • 作用:MyISAM 表的索引缓存(如果使用 MyISAM 表)。
  • 推荐值:若主要使用 InnoDB,可设为 64M~256M;若大量使用 MyISAM,需根据索引大小调整。

2. 连接与线程参数

max_connections
  • 作用:MySQL 允许的最大并发连接数。
  • 推荐值 :默认 151,通常调整为 500~2000 (需结合业务和 Threads_connected 监控)。
  • 面试追问
    • 连接数过多会导致什么问题?
      内存溢出(每个连接占用独立内存)、CPU 上下文切换开销大。
thread_cache_size
  • 作用:缓存空闲线程,避免频繁创建和销毁线程。
  • 推荐值 :根据 Threads_created 状态调整,通常设为 64~128

3. 事务与日志参数

innodb_flush_log_at_trx_commit
  • 作用:控制事务日志(Redo Log)的刷盘策略,平衡性能与数据安全。
  • 推荐值
    • 1(默认):每次事务提交都刷盘,保证 ACID,性能最低。
    • 02:每秒刷盘,性能高但可能丢失最近 1 秒的事务(用于非关键业务或从库)。
  • 面试追问
    • sync_binlog 的区别?
      sync_binlog 控制二进制日志(Binlog)的刷盘策略,两者共同影响数据一致性和性能。
sync_binlog
  • 作用:控制 Binlog 的刷盘频率。
  • 推荐值
    • 1(默认):每次事务提交刷盘,保证主从数据一致性。
    • 0:由操作系统决定刷盘时机,性能高但可能丢失数据。

4. 查询优化参数

tmp_table_sizemax_heap_table_size
  • 作用:控制内存临时表的最大大小。若临时表超过此值,会转为磁盘临时表(性能下降)。
  • 推荐值 :通常设为 64M~256M,需结合业务中复杂查询的临时表大小调整。
sort_buffer_sizejoin_buffer_size
  • 作用:排序和连接操作的内存缓冲区。
  • 推荐值:默认值(256KB~2MB)通常足够,避免全局设置过大(每个连接独立分配)。

5. InnoDB 存储引擎参数

innodb_log_file_size
  • 作用:Redo Log 文件大小,影响事务提交速度和崩溃恢复时间。
  • 推荐值 :通常设为 1~4G ,需保证 Redo Log 总大小(innodb_log_file_size * innodb_log_files_in_group)足够容纳 1~2 小时的写入量。
innodb_io_capacity
  • 作用:InnoDB 后台线程(如刷脏页)的 IO 吞吐能力。
  • 推荐值
    • HDD:200~500
    • SSD:2000~4000

6. 其他高频参数

table_open_cache
  • 作用:缓存已打开表的句柄数量,减少频繁打开表的开销。
  • 推荐值 :根据 Opened_tables 状态调整,通常设为 1024~4096
query_cache_typequery_cache_size
  • 注意:MySQL 8.0 已移除查询缓存!
  • 作用:缓存查询结果(适用于读多写少的场景)。
  • 问题:高并发写入场景下,查询缓存会因频繁失效导致性能下降,通常建议关闭。
相关推荐
倔强的石头_10 小时前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
阿巴斯甜16 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker16 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952717 小时前
Andorid Google 登录接入文档
android
黄林晴19 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android