MySQL八股篇
查询关键字执行先后顺序
-
FROM(及 JOIN
) -
WHERE
-
GROUP BY
-
HAVING
-
SELECT
-
DISTINCT
-
ORDER BY
-
LIMIT / OFFSET
CHAR 和 VARCHAR 的区别?使用场景?
MySQL窗口函数是什么
对数据集划分窗口(比如按组、按排序范围),在窗口内计算并返回每行对应的结果,不聚合数据,保留所有行
explain语句执行后生成的表重要字段含义
system
> const
> eq_ref
> ref
> range
> index
> ALL
idx_amount
;NULL
表示未命中索引(全表扫描)Using where
、Using index
(覆盖索引)、Using filesort
、Using temporary
等索引是什么?有什么好处?
-
是一种能高效获取数据的数据结构
-
可以提高数据检索效率,降低数据库的
I/O
成本 -
可以对数据进行排序,降低数据排序的成本,减少CPU的消耗
MySQL 索引失效的情况
- 模糊匹配时
%
开头
SELECT * FROM tbl WHERE name LIKE \'%ohn\';
- 对列进行函数运算或表达式计算
SELECT * FROM tbl WHERE DATE(created_at) = \'2025-06-27\';
- 字符串值不加引号,索引失效
-- phone 不加引号,索引失效explain select * from tb_user where phone = 17799990015;
or
两边条件,一边有索引,一边无索引,索引失效
-- id 有索引、age 无索引,索引失效explain select * from tb_user where id = 10 or age = 23;
MySQL索引使用会出现什么问题?该怎么解决?
问题:
-
索引维护成本高,影响写入性能, 解决: 减少索引数量, 批量提交写入操作,减少索引更新次数
-
索引未被使用(索引失效), 解决: 优化查询语句
-
索引占用过多磁盘空间 , 解决: 精简索引字段,清除无用索引
事务四大特性(ACID)及实现原理
Undo Log
)实现MVCC
(多版本并发控制)实现Redo Log
)实现并发事务问题
并发事务可能导致脏读、不可重复读和幻读
- 脏读是指一个事务读到了另一个事务未提交的“脏数据”
- 不可重复读是指在一个事务内多次读取同一数据,由于其他事务的修改导致数据不一致
- 幻读是指一个事务读取到了其他事务插入的“幻行”
事务隔离级别及实现原理
MySQL默认隔离级别
)事务隔离级别,每个级别会引发什么问题,MySQL 默认是哪个级别?
MySQL
默认事务隔离级别是可重复读
事务隔离级别引发的问题:
READ UNCOMMITTED
(读未提交)READ COMMITTED
(读已提交)REPEATABLE READ
(可重复读)SERIALIZABLE
(串行化)MySQL 常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
-
InnoDB
从MySQL 5.5
开始为默认存储引擎,综合事务处理能力和恢复性能最好。适合高并发读写、事务处理要求高的场景 -
MyISAM
适合读操作多、写操作较少, 对事务和数据完整性要求不高的场景 -
MEMORY
引擎速度最快,只作为短期缓存或临时表使用,不用于持久化业务数据
什么是聚簇索引什么是非聚簇索引?
-
聚簇索引是指数据与索引放在一起,
B+
树的叶子节点保存了整行数据,通常只有一个聚簇索引,一般是由主键构成 -
非聚簇索引则是数据与索引分开存储,B+树的叶子节点保存的是主键值,可以有多个非聚簇索引
回表查询是什么?
指的是通过二级索引找到对应的主键值,然后再通过主键值查询聚簇索引中对应的整行数据的过程
MySQL 中为什么推荐使用连接查询而不是子查询?
连接查询比子查询更高效、可读性更好, 因为连接查询不需要额外的中间临时表,但是子查询有中间临时表
什么叫覆盖索引?
-
指的是在
SELECT
查询中,返回的列都能在索引中找到 -
好处: 避免了回表查询,提高了性能。使用覆盖索引可以减少对主键索引的查询次数,提高查询效率
表的查询速度很慢,怎么解决?
-
使用
explain
分析sql
语句,找出原因 -
创建, 优化索引
-
优化数据库表,如果表数据量过大,可以拆成多张表
-
使用缓存
索引创建原则?
-
表中的数据量超过
10万
以上时考虑创建索引 -
选择查询频繁的字段作为索引,如查询条件、排序字段或分组字段
-
对于内容较长的字段使用前缀索引
-
控制索引数量,虽然索引可以提高查询速度,但会影响插入、更新的速度
-
尽量使用联合索引,覆盖
SQL
的返回值, 比如查询WHERE user_id=100 AND status=1
,创建(user_id, status)
的联合索引,比单独给两个字段建索引更能精准定位数据, 如果复合索引包含了 SELECT 语句需要返回的所有字段(如SELECT id, name FROM t WHERE user_id=100
,索引设为(user_id, id, name)
),数据库可以直接从索引中获取数据,无需再去表中查询(避免 “回表” 操作),大幅减少 IO 开销
SQL的优化手段
-
建表时选择合适的字段类型
-
使用索引,优化索引
-
编写高效的SQL语句,比如避免使用
SELECT *
,尽量使用UNION ALL
代替UNION
,以及在表关联时使用INNER JOIN
-
采用主从复制和读写分离提高性能
-
在数据量大时考虑分库分表
MySQL的binlog
- 二进制日志,记录所有数据库的写操作(
DDL/DML
) - 作用:主从复制(数据同步), 数据恢复(通过
mysqlbinlog
工具回放日志)
undo log 和 redo log 的区别是什么?
redo log
记录的是数据页的物理变化,用于服务宕机后的恢复,保证事务的持久性undo log
记录的是逻辑日志,用于事务回滚时恢复原始数据,保证事务的原子性和一致性
为什么使用B+ 树作为索引?而不用哈希表或二叉树
B+ 树
优势:
-
B + 树
的高度低, 磁盘IO
次数少 -
查询高效, 叶子节点形成有序链表,能够快速遍历
-
查询效率稳定, 所有查询路径长度相同,时间复杂度稳定为
O(log n)
对比其他结构:
-
哈希表不支持范围查询,哈希冲突影响性能
-
二叉树:树高较高,I/O次数多,可能退化为链表
日志与恢复
Redo Log
Undo Log
BinLog
事务中的隔离性是如何保证的呢?(解释下MVCC)
事务的隔离性通过锁和多版本并发控制(MVCC)来保证。MVCC 通过维护数据的多个版本来避免读写冲突。底层实现包括隐藏字段、undo log
和read view
。隐藏字段包括trx_id
和roll_pointer
。undo log
记录了不同版本的数据,通过roll_pointer
形成版本链。read view
定义了不同隔离级别下的快照读,决定了事务访问哪个版本的数据。
MySQL主从同步原理是什么?
MySQL主从复制的核心是二进制日志(Binlog)。步骤如下:
-
主库在事务提交时记录数据变更到Binlog
-
从库读取主库的Binlog并写入中继日志(Relay Log)
-
从库重做中继日志中的事件,反映到自己的数据中
执行一条SQL的流程
- 连接器:验证用户权限,建立连接
- 查询缓存:检查缓存(MySQL 8.0已移除)
- 解析器:语法分析,生成抽象语法树(AST)
- 优化器:选择最优执行计划(如索引选择、JOIN顺序)
- 执行器:调用存储引擎接口执行计划
- 存储引擎(如InnoDB):
- 从内存(Buffer Pool)或磁盘读取数据
- 写入Redo Log和Undo Log
- 返回结果:将结果返回客户端
如何在MySQL中查看慢查询?
-
开启慢查询日志
-
使用
SHOW PROCESSLIST
实时监控