MySQL数据库管理-核心知识点总结V1
1 B+树
MySQL 的 InnoDB 默认使用 B+ 树实现索引。相比二叉树和红黑树,B+ 树是多路查找树,树高更低,更适合磁盘 IO。相比 B 树,B+ 树把数据集中放在叶子节点,非叶子节点能存更多 key,因此路径更短;同时叶子节点之间通过链表连接,范围查询和排序扫描效率更高。所以 InnoDB 选择 B+ 树,是为了降低磁盘读写成本、提升查询稳定性,并更好支持范围查询。
2 分析优化
我会先通过链路追踪或监控确认慢点是不是数据库访问。如果确认是 SQL 慢,再看慢查询日志定位具体 SQL。拿到 SQL 后用 EXPLAIN 分析执行计划,重点看 type、key、key_len、rows、Extra。如果是全表扫描,就检查查询条件和索引设计;如果有回表,就看能否用覆盖索引或减少返回字段;如果有 filesort 或 temporary,就优化排序分组字段和联合索引;如果是深分页,就考虑覆盖索引加子查询或基于游标翻页。最后压测或对比执行计划,验证优化是否真的生效。
覆盖索引与回表
InnoDB 的聚簇索引是数据和索引放在一起的索引,叶子节点保存整行数据,一张表只有一个,通常就是主键索引。二级索引的叶子节点保存索引列和主键值。如果通过二级索引查询,但要返回的列不在二级索引中,就需要拿主键再去聚簇索引查整行数据,这叫回表。覆盖索引指的是查询要返回的字段都能从索引中拿到,可以避免回表。所以实际优化时,要尽量避免select *,并结合高频查询设计合适的联合索引。
3 索引设计
索引设计要结合数据量、查询频率、字段区分度和排序分组场景。常用作 where、order by、group by 的高区分度字段适合建索引,长字符串可以考虑前缀索引,高频组合查询可以建联合索引并尽量覆盖查询字段。索引失效常见原因有违反最左前缀、范围查询右侧列无法继续使用、在索引列上做函数或运算、字符串不加引号、like 以百分号开头。深分页慢是因为 MySQL 需要扫描并丢弃大量前置记录,可以用覆盖索引加子查询,或者改成基于游标的分页。
覆盖索引加子查询优化
一种常见优化思路是先用覆盖索引查出目标页的主键,再回表取完整数据。
SELECT t.*FROM tb_sku tJOIN (SELECT idFROM tb_skuORDER BY idLIMIT 9000000, 10) a ON t.id = a.id;
索引优化的核心是“让 MySQL 少扫描、少排序、少回表”。建索引前先看业务查询,写 SQL 时避免破坏索引使用,遇到深分页时减少无效扫描。最后一定用EXPLAIN验证,而不是凭感觉判断。
5 MYSQL外键可能导致大量的阻塞,系统崩溃
外键可能导致大批量的堵塞。原因就是外键会加 SELECT ... FOR SHARE
这两个概念的区别非常大。简单来说,普通 SELECT 是“和平的”,它不加锁;而 SELECT ... FOR SHARE 是“带有防御性的”,它会给数据加上一把共享锁(S锁)。
我们可以从以下几个核心维度来看看它们的具体区别:
🔒 加锁机制不同(最核心的区别)
* 普通 SELECT:不加任何锁。它使用的是 MVCC(多版本并发控制)技术,读取的是数据在某个时间点的“快照”。
* SELECT ... FOR SHARE:会给查询到的行加上共享锁(S锁)。这意味着,其他事务依然可以读取这些行(也可以继续加共享锁),但是绝对不能修改或删除这些行,必须等待你的事务提交或回滚释放锁之后才行。📖 读取到的数据不同
* 普通 SELECT:在默认的事务隔离级别(可重复读)下,它读取的是事务开始时的历史快照。即使此时有其他事务正在修改这行数据但还没提交,你看到的依然是修改前的旧数据。
* SELECT ... FOR SHARE:它读取的是最新的数据。如果这行数据正在被其他事务修改(且未提交),你的 SELECT ... FOR SHARE 会被堵塞,一直等到对方事务结束后,读取到最新的值才会返回。🎯 适用场景不同
* 普通 SELECT:适用于绝大多数的只读查询,比如展示商品列表、生成报表、查询用户信息等。因为它不加锁,数据库的并发性能最高。
* SELECT ... FOR SHARE:适用于“我要读最新数据,且在我处理完之前,绝不允许别人修改它”的场景。
* 比如:你要根据父表的数据在子表中插入一条关联记录。为了确保在你插入时,父表的那条数据不会被其他事务删掉,你就可以先用 SELECT ... FOR SHARE 把父表记录锁住。为了让你看得更直观,我为你整理了一个对比表格:
维度 普通 SELECT SELECT ... FOR SHARE
加锁情况 不加锁(无锁读取) 加共享锁(S锁)
别人能否读 可以 可以(共享锁之间兼容)
别人能否改 可以(互不影响) 不可以(会被堵塞)
读取的数据 历史快照(可能是旧数据) 最新数据(会等对方改完)
主要用途 绝大多数日常查询 需要保护数据不被并发修改的读取补充一个小细节:SELECT ... FOR SHARE 是 MySQL 8.0 引入的新语法,在老版本的 MySQL 中,它等价于 SELECT ... LOCK IN SHARE MODE。
本文主要是用于自己学习使用,总结内容转自微信公主号:
