MySQL 八股文【持续更新ing】
MySQL 八股文【持续更新ing】
文章目录
- MySQL 八股文【持续更新ing】
- 前言
- 一、MySQL的存储引擎有哪些?他们之间有什么区别?
- 二、MySQL `InnoDB 引擎中`的聚簇索引和非聚簇索引有什么区别?
- 1.InnoDB 中的聚簇索引
- 2.InnoDB 中的非聚簇索引
- 三、MySQL的索引类型有哪些?
- 四、为什么MySQL选择使用 B+ 树作为索引结构?
- 五、MySQL索引的最左匹配原则是什么?
- 六、MySQL 三层 B+ 树能存多少数据?
- 七、MySQL中的回表是什么
- 八、MySQL中使用索引一定有效吗?如何排查索引效果?
- 九、在MySQL中建索引时需要注意哪些事项?
- 十、MySQL中的索引数量是否越多越好?为什么?
- 十一、如何使用MySQL的Explain语句进行查询分析?
- 十二、MySQL中如何进行SQL调优?
前言
一名27届后端开发选手的八股学习日常总结。
一、MySQL的存储引擎有哪些?他们之间有什么区别?
- InnoDB存储引擎
特点:- 支持事务(ACID)(通过begin、commit、rollback 控制)
- A(Atomicity)原子性
- C(Consistency)一致性
- I(Isolation)隔离性
- D(Durability)持久性
- 支持行级锁(从锁粒度来划分)
- 通过对索引项加锁来实现行级锁、如果查询条件没有建立索引则会升级为表级锁。
- 外键约束
- 支持聚簇索引、提高检索效率
- 默认用
表的主键
建立聚簇索引 - 没有主键则去查找
唯一非空属性
建立聚簇索引 - 没有
唯一非空属性
则使用隐藏的Row_id
建立聚簇索引 - B+树实现
- 聚簇索引的B+树叶子结点存放数据本身,非叶子节点不存放数据(进存放索引,例如:主键id)
- 默认用
- 支持MVCC(多版本并发控制)来提高数据库的并发性能,保证事务的ACID。
- 提供
undolog
和redolog
来实现回滚和崩溃恢复
- 支持事务(ACID)(通过begin、commit、rollback 控制)
- MyISAM存储引擎
特点:- 不支持事务、外键
- 仅支持表级锁(不支持行级锁)
- 支持非聚簇索引,不支持聚簇索引
- 也是B+树实现
- 非聚簇索引的B+树叶子结点存放数据行地址(索引文件和数据文件分开存放)
- 适合 读取多、更新少的场景,例如数据仓库
- 具有较高的读性能和较快的表级锁定
- Memory存储引擎
- 是内存存储引擎,数据存储在内存中,服务重启数据会丢失
- 仅支持hash索引(存储在内存中)
- 适用于临时数据存储或快速缓存
- 存放一些公共的、常用的、且不经常发生改变的数据
- NDB(NDBCluster)
- 支持高可用性和数据分布,适合大规模分布式应用
- 提供行级锁和自动分区
二、MySQL InnoDB 引擎中
的聚簇索引和非聚簇索引有什么区别?
1.InnoDB 中的聚簇索引
- 聚簇索引的B+树的叶子节点中存放的是数据行、非叶子节点存放的的是索引
- 叶子结点包含所有的数据
- 每一个表只能有一个聚簇索引,通常是主键索引,如果没有设定主键,回去选择一个唯一非空列作为索引去建立聚簇索引,如果也不存在唯一非空列,则使用隐藏的Row_id作为索引
- 适合于范围查询和排序
2.InnoDB 中的非聚簇索引
- InnoDB中的非聚簇索引的索引叶子节点存储的是数据行的主键和对应的索引列,需要通过主键进行回表查询完整的数据行
- 一个表中可以有多个非聚簇索引(这里又称为 非主键索引、辅助索引、二级索引),适合快速查找特定列的数据
三、MySQL的索引类型有哪些?
按照数据结构划分:
- B+树索引
- hash索引
- 全文索引(倒排索引)
从常见的基于 InnoDB B+树 索引角度来看,分为:
- 聚簇索引
- 非聚簇索引
按照索引性质划分:
- 普通索引(二级索引、辅助索引)
- 主键索引
- 联合索引
- 唯一索引
- 全文索引
四、为什么MySQL选择使用 B+ 树作为索引结构?
- 高效的查询性能
- B+ 树是一种自平衡树,每个叶子结点到根节点的路径长度相同,B+ 树在插入和删除节点时会进行分裂和合并操作,以保持树的平衡,但是他有一定的冗余节点,使得删除的时候树结构的变化小,更高效
- 查找、插入、删除等操作的时间复杂度为O(logn)
- 树的高度增长不会过快,这样可以减少查询磁盘的IO次数
- B+ 树不像红黑树,数据越多树的高度增长就越快。B+ 树是多叉树,非叶子节点仅保存主键或索引值和页面指针,使得每一页能容纳更多的记录,因此内存中可以放更多索引
- 范围查询能力强
- B+ 树特别适合范围查询,因为叶子结点通过双向链表连接,从根节点定位到叶子结点查找的范围的起点之后只需要顺序扫描链表即可完成后续的数据遍历
五、MySQL索引的最左匹配原则是什么?
MySQL索引的最左匹配原则指的是:在使用联合索引时,查询条件必须按照索引建立的顺序去筛选,例如建立索引的顺序是(a、b、c),那么作为条件查询的时候应该尽量保持
where a = ? and b = ? and c ...
。
底层原理:
MySQL建立的联合索引中,是按照顺序建立的,例如联合索引(first_name,last_name,age)的排列方式大致示意图:
(Alice, Black, 35)|-------------------------------------------------------------| | | |(Alice, Brown, 25) (Alice, Smith, 30) (Bob, Smith, 20) (Bob, White, 19)
六、MySQL 三层 B+ 树能存多少数据?
在MySQL的InnoDB存储引擎中,B+树默认数据页大小是一页 16kB。
聚簇索引中,每一个非叶子结点中存放:
- 索引键(一般取 主键id:bigInt --> 8B)、每个指针(6B),那么每个中间节点可以存放(16kB /(6B + 8B)) = (16 * 1024 B) / (14B)= 1170
- 即每一层的中间节点都可以指向1170个子节点。
- 最后叶子结点的个数为:1170 * 1170 * 16 = 21902400,一棵三层的B+ 树在MySQL中可以存储大约2000万条记录。
图示:
七、MySQL中的回表是什么
回表一般是指在使用InnoDB引擎的二级索引(非聚簇索引)作为条件进行查询时,由于二级索引中只存储了索引字段的值和对应的主键值,无法得到其他数据,如果要查询数据行中的其他数据,需要根据主键去聚簇索引中查找实际的数据行,这个过程叫做回表。
注意:仅仅是指InnoDB中的非聚簇索引中,MyISAM中的非聚簇索引是数据文件和索引文件分开存放,不存在回表的概念。
八、MySQL中使用索引一定有效吗?如何排查索引效果?
- 不一定,索引可能会失效,索引常见失效情况如下:
- 查询条件中破坏了最左匹配原则(没有按照索引建立顺序且使用了范围查询,或者使用了没有建立索引的列)
- 索引列参与了计算或者函数
- not in 和 not exists使用不当
- 某些情况下的数据类型强制转换
- 。。。
- 一般使用Explain关键字去查看索引使用情况
explain select ....
其中下面这些列可以看出走索引的情况- type:表示查询时数据访问方式:性能从优到劣排序如下:
- system > const > eq_ref > ref > range > index > all
- system:表中仅一行数据(系统表)。
- const:通过主键或唯一索引查到一行数据(如
WHERE id = 1
)。 - eq_ref:唯一索引关联(如
JOIN
时使用主键匹配)。 - ref:非唯一索引查找(可能返回多行)。
range(优化目标)
:索引范围扫描(如BETWEEN
、IN
)。- index:全索引扫描(遍历索引树)。
- ALL:全表扫描(需优化)。
- system > const > eq_ref > ref > range > index > all
- key:实际使用到的索引
- 若为null,则表示未使用索引
- key_len:索引使用的字节数,反应索引字段的利用率
- 可以根据建立的索引列属性计算出哪些索引被用上了
- Extra:表示附加信息,反应执行细节。
- Using where:使用
WHERE
过滤数据。 - Using index:覆盖索引(无需回表)。
- Using temporary:使用临时表(常见于排序或分组)。
- Using filesort:
外部排序(需优化索引)
。 - Using join buffer:使用连接缓冲区(关联字段无索引)。
- Using where:使用
九、在MySQL中建索引时需要注意哪些事项?
- 索引不是越多越好,索引会占用存储空间,每次修改都需要维护索引中的数据,也会耗时
- 字段值大量重复的字段不要建立索引,例如:性别字段
- 长字段不应该建立索引,因为占据的内存大,扫描的时候比较耗时,可以考虑建立前缀索引
- 当表的修改频率远大于查询频率是,应该考试是否建立索引
- 对于需要频繁作为条件查询的字段应该建立索引,且可以考虑优先建立联合索引,减少索引数量,利用覆盖索引提高效率,避免回表查询
- 对经常在order by、group by、distinct 后面的字段建立索引,加快效率
十、MySQL中的索引数量是否越多越好?为什么?
索引并不是越多越好。
- 每建立一个索引都需要新建一个B+树,所以如果索引过多会占据很大的空间
- 对于索引的更新操作会导致B+树进行节点的修改、旋转,如果修改操作较多,比较耗时,并且B+树可能会有页分裂、合并等操作,时间开销上面会更大
十一、如何使用MySQL的Explain语句进行查询分析?
直接在查询语句前面加上 Explain关键字即可
输出的列表示的含义:
1. id
- 作用:标识查询中
SELECT
的执行顺序。 - 规则:
id
相同:执行顺序从上到下(如多表关联查询)。id
不同:值越大优先级越高,越先执行(如子查询)。id
为NULL
:表示是其他查询的联合结果(如UNION
)。
2. select_type
- 作用:表示
SELECT
的类型,反映查询的复杂度。 - 常见值:
- SIMPLE:简单查询(无子查询或
UNION
)。 - PRIMARY:外层主查询。
- SUBQUERY:子查询中的第一个
SELECT
。 - DERIVED:派生表(例如
FROM
子句中的子查询)。 - UNION:
UNION
中的第二个或之后的SELECT
。 - UNION RESULT:
UNION
的结果集。
- SIMPLE:简单查询(无子查询或
3. type
- 作用:数据访问方式,性能从优到劣排序如下:
- system:表中仅一行数据(系统表)。
- const:通过主键或唯一索引查到一行数据(如
WHERE id = 1
)。 - eq_ref:唯一索引关联(如
JOIN
时使用主键匹配)。 - ref:非唯一索引查找(可能返回多行)。
range(优化目标)
:索引范围扫描(如BETWEEN
、IN
)。- index:全索引扫描(遍历索引树)。
- ALL:全表扫描(需优化)。
4. table
- 作用:显示当前行操作的表名。
- 特殊值:
<derivedN>
:派生表(来自 id 为 N 的子查询)。<unionM,N>
:UNION
结果(由 id 为 M 和 N 的查询合并)。
5. possible_keys
- 作用:可能用到的索引列表。
- 注意:若为
NULL
,说明没有适合的索引,需检查表结构或查询条件。
6. key
- 作用:实际使用的索引。
- 注意:
- 可能不在
possible_keys
中(优化器可能选择更优索引)。 - 若为
NULL
,表示未使用索引(全表扫描)。
- 可能不在
7. key_len
- 作用:索引使用的字节数,反映索引字段的利用率。
- 计算规则:
- 字符串类型:
长度 × 字符集字节数
(如VARCHAR(255) UTF8MB4
最大长度为255 × 4 + 2 = 1022
)。 - 数值/时间类型:固定长度(如
INT
为 4 字节)。
- 字符串类型:
8. ref
- 作用:显示与索引比较的列或常量。
- 常见值:
const
:常量值(如WHERE id = 1
)。- 列名(如
WHERE t1.col = t2.col
)。
9. rows
- 作用:预估需要扫描的行数(越小越好)。
- 注意:基于统计信息估算,可能与实际值有偏差。
10. partitions
- 作用:匹配的分区(若表未分区则为
NULL
)。 - 适用场景:针对分区表的查询优化。
11. filtered
- 作用:查询条件过滤后剩余数据的百分比。
- 用途:估算与其他表关联时需处理的行数(
rows × filtered
)。
12. Extra
- 作用:附加信息,反映执行细节。
- 常见值:
- Using where:使用
WHERE
过滤数据。 - Using index:覆盖索引(无需回表)。
- Using temporary:使用临时表(常见于排序或分组)。
- Using filesort:外部排序(需优化索引)。
- Using join buffer:使用连接缓冲区(关联字段无索引)。
十二、MySQL中如何进行SQL调优?
通过慢查询日志找到执行速度比较慢的查询语句然后利用explain分析查询语句的执行计划,优化查询语句。
- 合理设计索引,多用联合索引来代替单个索引,尽量走索引覆盖查询,避免回表次数
- 避免索引失效的几种情况
- 避免使用 select *
- 遵循最左匹配原则来查询
- 避免索引列上的强制类型转换
- 避免使用前缀模糊查询 like ‘%…’
- 避免索引列参与计算
- 利用Redis缓存来优化MySQL效率,将频繁访问的数据放到缓存中减少数据库的压力。
。。。