1.解释一下MySQL中InnoDB的ACID特性?
原子性(Atomicity ):事务是一个不可分割的最小操作单元,要么全部成功,要么全部失败 。InnoDB通过Undo Log实现原子性。如果事务失败,Undo Log 会记录修改前的数据,用于回滚 。
一致性(Consistency ):事务执行前后,事务执行前后数据逻辑一致 。例如,转账操作中总金额不变。一致性由应用层和数据库共同保证。靠原子性、隔离性、持久性共同保障。
隔离性(Isolation ):多个并发事务之间互不干扰 。InnoDB通过锁机制和MVCC(多版本并发控制)实现隔离性。
持久性(Durability ):事务提交后,修改永久保存到数据库。InnoDB通过Redo Log实现持久性。Redo Log记录修改后的数据,即使系统崩溃也能恢复。
2.MySQL中的4种事务隔离级别是什么?
读未提交(Read Uncommitted):事务可以读取其他未提交事务的修改。存在脏读、不可重复读、幻读问题。
读已提交(Read Committed):事务只能读取已提交的数据。解决脏读,但存在不可重复读和幻读(通过MVCC实现)。
可重复读(Repeatable Read):事务内多次读取同一数据结果一致。解决不可重复读,但存在幻读(InnoDB通过Next-Key Locks解决幻读)。
串行化(Serializable):所有事务串行执行,无并发问题,但性能极低。
MVCC:通过ReadView和Undo Log版本链实现多版本控制。
锁机制:如间隙锁(Gap Lock)防止幻读。
InnoDB的Next-Key Locks是记录锁(Record Lock)和间隙锁(Gap Lock)的结合:
记录锁:锁定索引中的特定行。
间隙锁:锁定索引记录之间的间隙,阻止其他事务在间隙中插入数据。
Next-Key Lock:锁定一个左开右闭区间(例如(10, 15]),包含记录本身及其之前的间隙。
3.MySQL中有哪些索引?索引的数据结构是什么?为什么使用B+树?B树和红黑树不行吗?
索引类型:主键索引、唯一索引、普通索引、联合索引、全文索引、空间索引。
数据结构:B+树:InnoDB默认的索引结构。
优势:
磁盘IO优化:B+树非叶子节点只存键值,单次IO可加载更多数据。
范围查询高效:叶子节点形成有序链表,适合范围扫描。
高度平衡:所有叶子节点在同一层,查询稳定。
对比B树:B树每个节点存数据,导致单次IO加载的键值更少,范围查询需多次回溯。
对比红黑树:红黑树是二叉树,高度更高(例如百万数据需要20层),导致更多磁盘IO。
4.用了索引还是很慢,可能是什么原因?
索引失效 :如对索引列使用函数、类型转换、OR条件包含非索引列。
回表查询 :联合索引未覆盖查询字段,需回表查主键索引。
数据分布不均 :索引区分度低(如性别字段),优化器可能选择全表扫描。
锁竞争 :事务长时间持有锁,导致查询阻塞。
统计信息不准确:优化器误判索引成本,需手动ANALYZE TABLE更新统计信息。
5.为什么树的层数不能超过3层。
B+树高度与性能:假设单页16KB,主键为BIGINT(8B),指针6B,则单页可存 16KB/(8B+6B)=1170 个键值。
3层B+树可存储 1170 * 1170 * 16 ≈ 2000万 条数据。
超过3层后,查询需要更多磁盘IO,性能显著下降。
6.sql性能优化问题,一般到达那个索引级别会比较好
索引访问类型(由EXPLAIN的type字段显示):
const:主键或唯一索引的等值查询(最优)。
ref:普通索引的等值查询。
range:索引范围扫描(如BETWEEN、>)。
index:全索引扫描(需避免)。
ALL:全表扫描(最差)。
优化目标:至少达到range级别,理想是ref或const。
7.有什么情况会索引失效?如何解决?
索引列参与运算 :如WHERE id + 1 = 10。
使用函数 :如WHERE UPPER(name) = 'ABC'。
隐式类型转换 :如字符串列用数字查询WHERE id = '100'。
OR条件包含非索引列 :如WHERE a=1 OR b=2,若b无索引则全表扫描。
联合索引未遵循最左前缀:如索引(a,b,c),但查询条件无a。
8.什么是回表?回表发生在什么索引中?什么是索引覆盖?什么是索引下推?
回表:通过普通索引查到主键后,需回主键索引查询完整数据。发生在非聚簇索引中。
索引覆盖:查询字段全部在索引中,无需回表。例如联合索引(a,b)查询a和b。
索引下推(ICP):MySQL 5.6+特性,将WHERE条件下推到存储引擎层过滤,减少回表次数。例如联合索引(a,b)查询a>1 AND b=2,存储引擎会先过滤b=2。
9.MySQL中binlog、redolog、undolog的区别?
| 属性 | binlog | redolog | undolog |
|---|---|---|---|
| 作用 | 逻辑日志,用于主从复制和数据恢复 | 物理日志,保证事务持久性 | 逻辑日志,用于事务回滚和MVCC |
| 层级 | Server层 | InnoDB引擎层 | InnoDB引擎层 |
| 内容 | SQL语句或行变更事件 | 数据页的物理修改 | 数据修改前的版本写入 |
| 写入时机 | 事务提交后异步写入 | 事务执行中持续写入(WAL机制) | 事务执行中记录 |
10.MySQL中索引设计原则?
选择高区分度字段 :如用户ID而非性别。
联合索引最左前缀 :将高频查询字段放在左侧。
避免过多索引 :索引增加写操作开销。
覆盖索引优化 :减少回表查询。
考虑排序和分组:索引顺序与ORDER BY或GROUP BY一致。
11.聚簇索引和非聚簇索引的区别
聚簇索引:叶子节点存储数据行(如InnoDB的主键索引)。一张表只能有一个聚簇索引。
非聚簇索引:叶子节点存储主键值(如普通索引),需回表查询数据。
12.请描述下数据库的锁,锁的分类有哪些?
按粒度:
行锁:锁定单行(InnoDB默认)。
表锁:锁定整表(如MyISAM)。
间隙锁(Gap Lock):锁定范围,防止幻读。
按模式:
共享锁(S锁):读锁,允许其他事务读。
排他锁(X锁):写锁,禁止其他事务读写。
按实现:
意向锁:表级锁,表明事务即将对行加锁。
13.update在mysql的执行流程是什么样的
连接器:验证权限。
分析器:解析SQL语法。
优化器:选择索引,生成执行计划。
执行器:
从存储引擎读取数据(若使用索引)。
调用InnoDB引擎接口修改数据。
写入Undo Log(用于回滚)和Redo Log(保证持久性)。
两阶段提交:先写Redo Log(prepare状态),再写Binlog,最后提交事务。
14.count(1) count(*) count(字段)的区别
COUNT():统计所有行数(包括NULL),优化后直接读行数。
COUNT(1):与COUNT( )性能相同,统计所有行。
COUNT(字段):统计该字段非NULL的行数,需回表检查字段值。
count(1)底层会优化成count(*)
15.MySQL中索引类型有哪些?
主键索引、唯一索引、普通索引、联合索引、全文索引(FULLTEXT)、空间索引(SPATIAL)。
16.介绍一下MVCC机制?记忆锚点:
核心:隐藏字段 + undo log 版本链 + Read View→无锁读;
流程:Read View 判断版本可见性,遍历版本链找可见数据。
面试表达模板:
"事务的隔离性靠锁和 MVCC,MVCC 是多版本并发控制,能实现'读不加锁,写不阻塞读' ,底层有 3 个核心组件:
第一个是隐藏字段,每行数据有 trx_id(最后修改的事务 ID)和 roll_pointer(指向 undo log 的指针);
第二个是 undo log 版本链,每次修改数据都会生成新的 undo log,用 roll_pointer 连起来 ,比如数据被事务 1、2 修改,版本链就是事务 2→事务 1→原始数据;
第三个是 Read View,事务启动时生成的快照,记录当前活跃的事务 ID。比如事务 A 启动时,Read View 里活跃事务 ID 是 [2,3],查数据时会从最新版本开始遍历版本链:如果 trx_id 比活跃事务最小 ID 还小,说明这个事务已经提交了,数据可见,就返回;如果 trx_id 在活跃事务里,说明事务还没提交,数据不可见,继续找下一个版本。这样就能保证事务 A 看到的是启动时的快照,不会被其他事务的修改干扰,实现隔离性。"
17.描述一下MySQL主从复制过程?如何解决主从复制延迟?
主库:将数据变更写入Binlog。
从库:IO线程拉取Binlog到中继日志(Relay Log)。
从库:SQL线程重放Relay Log中的事件。
延迟解决:
并行复制(按库或按事务分组)。
半同步复制(主库等待至少一个从库确认)。
分库分表减少单库压力。
18.MySQL中死锁问题如何解决?如何排查慢SQL问题?
死锁解决:
设置innodb_lock_wait_timeout(锁超时时间)。
启用innodb_deadlock_detect(自动检测并回滚代价小的事务)。
慢SQL排查:
开启慢查询日志(slow_query_log)。
使用EXPLAIN分析执行计划。
优化索引或重写SQL。
19.如何优化MySQL中深度分页?
问题:LIMIT 1000000,10需扫描前100万行。
优化方案:
使用覆盖索引+子查询:SELECT * FROM table WHERE id > (SELECT id FROM table LIMIT 1000000,1) LIMIT 10。
记录上次查询的最大ID:WHERE id > last_max_id LIMIT 10。
20.如何优化一个大规模的数据库系统?
垂直拆分:按业务模块分库(如用户库、订单库)。
水平拆分:分表(如按用户ID哈希)。
读写分离:主库写,从库读。
缓存:使用Redis缓存热点数据。
硬件优化:SSD、增加内存。
SQL优化:避免全表扫描,减少JOIN操作。