MySQL相关八股(260330笔记)
Mysql存储引擎
主索引(聚簇索引)将数据存储在叶子节点,辅助索引存储指向主键的指针
# 什么是存储过程?
**存储过程(Stored Procedure)** 是**数据库中预先编译好、存储在服务器上的一组 SQL 语句集合**,你可以把它理解成**数据库里的“自定义函数/小程序”**。
它提前把复杂的 SQL 逻辑(增删改查、循环、判断、事务等)写好并保存,需要使用时,直接调用名字就能执行,不用重复写代码。
一、用最简单的比喻理解
你要做一道菜:
- 普通 SQL:每次都把所有食材、步骤写一遍,一步步操作;
- 存储过程:把完整菜谱提前存在厨房,想吃的时候喊一声菜名,厨师直接按菜谱做好。
二、核心特点
- 存储在数据库服务器
不是写在你的代码里,而是保存在 MySQL、Oracle、SQL Server 等数据库中。 - 预先编译
第一次执行后就编译好了,后续调用速度更快。 - 可重复调用
一次编写,无数次使用,程序、报表、脚本都能直接调用。 - 支持参数、逻辑判断、循环
能实现复杂业务逻辑,不只是简单查询。 - 减少网络传输
不用把一大段 SQL 发给服务器,只发一个调用指令。
三、一个极简示例(MySQL)
1. 创建一个简单的存储过程
1 | -- 创建存储过程:根据用户ID查询用户名 |
2. 调用存储过程
1 | -- 调用:传入ID=1,返回用户名 |
3. 说明
IN:输入参数(你传给存储过程的值)OUT:输出参数(存储过程返回给你的结果)- 调用时只用
CALL 存储过程名(参数),非常简洁
四、为什么要用存储过程?(优点)
- 提高执行速度
预编译,避免重复解析 SQL。 - 减少网络流量
只传调用指令,不传整段 SQL。 - 代码复用,便于维护
逻辑统一修改,不用到处改代码。 - 安全可控
可以给用户分配执行存储过程的权限,不直接开放表权限。 - 适合复杂业务
支持事务、循环、条件判断,能处理复杂逻辑。
五、缺点(也要知道)
- 不同数据库语法不通用(MySQL 写的不能直接在 Oracle 用);
- 调试比普通代码麻烦;
- 过多复杂存储过程会加重数据库服务器负担。
总结
- 存储过程 = 数据库里的预编译 SQL 程序
- 一次编写,反复调用,高效、安全、简洁
- 适合复杂、频繁执行的数据库逻辑
- 主流数据库(MySQL、Oracle、SQL Server)都支持
datetime:不受时区影响,绝对时间,占8个字节,手动更新
timestamp:受时区影响,相对时间,占4个字节,自动更新
在 MySQL 中,Boolean 类型通常用TINYINT(1)表示,Boolean并不是一个真实存在的引擎
# MySQL 存文章:别用 BLOB,TEXT 完全可以用!
先给你一个**最直接、最实用的结论**:
**存文章、长文本,MySQL 首选 `TEXT` 系列类型,完全没问题,根本不用避开!**
“不推荐 TEXT/BLOB”,是有前提条件的
一、先辟谣:为什么有人说“不推荐 TEXT/BLOB”?
他们说的坑,主要是这 3 点:
- 临时表不能放内存:查询如果用到 TEXT/BLOB,MySQL 只能用磁盘临时表,比内存慢
- 行溢出:大文本会让数据行跨页存储,读取整行时变慢
- 索引限制:不能直接给 TEXT 建全索引,只能建前缀索引
但!这些问题对「存文章」几乎不影响!
文章是一次写入、多次读取、很少修改的场景,完全适配 TEXT。
二、存文章,MySQL 官方推荐的类型
按文章长度从小到大选,直接套用:
| 类型 | 最大容量 | 适用场景 |
|---|---|---|
| TINYTEXT | 255 字符 | 简介、摘要、小标题 |
| TEXT | 64KB | 短篇文章、博客、笔记(最常用) |
| MEDIUMTEXT | 16MB | 长文、小说、文档 |
| LONGTEXT | 4GB | 超大内容(一般不用) |
✅ 日常写博客、文章、内容:直接用 TEXT 就够了
✅ 超长文章:用 MEDIUMTEXT
三、真正正确的存储方案(生产环境通用)
1. 最佳表结构设计
1 | CREATE TABLE articles ( |
2. 关键优化(解决 TEXT 的小缺点)
不要把 TEXT 字段放在 SELECT * 里查
1
2
3
4
5
6
7
8-- 差
SELECT * FROM articles;
-- 好(列表页只查需要的字段)
SELECT id, title, create_time FROM articles;
-- 详情页再查 content
SELECT content FROM articles WHERE id=?;常用字段和 TEXT 字段分离
列表高频字段放主表,大文本放副表(垂直拆分),性能起飞。不要给 content 建索引
文章全文搜索用 ES/Meilisearch,别用 MySQL 索引。
四、那 BLOB 什么时候用?永远别存文章!
BLOB 是二进制类型,用来存:
- 图片
- 文件
- 音频视频
存文本绝对不要用 BLOB:
- 不支持字符集
- 不支持排序、模糊查询
- 占空间更大
- 读取性能更差
五、终极总结(一句话记住)
- 存文章/长文本 → 用 TEXT / MEDIUMTEXT(完全推荐)
- 存文件/图片 → 用 BLOB(但更推荐存路径,文件放磁盘/OSS)
- VARCHAR 只存短文本(标题、昵称)
总结
- TEXT 是存文章的标准方案,放心大胆用
- 所谓“不推荐 TEXT”是针对高频更新、超大表的特殊场景
- 文章内容 = TEXT / MEDIUMTEXT,标题 = VARCHAR,文件 = 存路径
- 只要不
SELECT *,性能完全没问题
数据库视图是基于一个或多个表的查询结果创建的虚拟表,用于简化复杂查询、提高数据安全性和提供数据抽象。
数据库游标是一种数据库对象,用于逐行处理查询结果集,允许在结果集中进行遍历、检索、更新和删除操作,适合需要逐行处理数据的场景。
数据库三大范式
数据库的三大范式是:
- 第一范式(1NF):确保每列的值都是不可分割的原子值。
- 第二范式(2NF):在满足第一范式的基础上,确保每个非主属性完全依赖于主键。
- 第三范式(3NF):在满足第二范式的基础上,确保每个非主属性不传递依赖于主键。
hash索引和b+树索引
Hash索引是基于键值对的,通过键的哈希值直接查询存储的指。而BTree是根据索引字段值的大小关系去有序存储,BTree的查询是不断缩小查找范围,最终得到查找的数据。两者相比,hash的查找速度更快,但是也没有快很多,这也看BTree层数的高度和数据量的大小,但是BTree更适合范围查找,通过数据的有序性,查询某一段区间的数据会更快。
B+ 树的叶子节点按顺序链接,支持快速的范围查询。
B+ 树节点大小与磁盘一次读取的最小单位(磁盘页)大小匹配,减少磁盘 I/O 操作。
如何判断 MySQL 索引是否失效(超实用指南)
判断索引是否失效,核心方法只有一个:用 EXPLAIN 查看执行计划,再结合失效场景快速定位原因。
我给你整理了最实用、工作中直接能用的判断方法 + 失效场景,一看就会。
一、最快判断:用 EXPLAIN 看这 3 个字段
直接在你的查询前加 EXPLAIN,例如:
1 | EXPLAIN SELECT * FROM user WHERE name = '张三'; |
重点看这 3 列,就能 100% 判断索引是否生效:
1. type(最重要)
- ALL:全表扫描 = 索引完全失效
- index / range / ref / eq_ref:索引有效
2. key
- NULL:没有使用任何索引 = 失效
- 显示索引名:使用了索引
3. rows
- 数字越大,说明索引越差(接近全表扫描)
二、索引失效的 9 个最常见场景(背会直接用)
1. 对索引列使用函数 / 运算(最常见)
1 | -- 失效 |
2. 模糊查询以 % 开头
1 | -- 失效 |
3. 使用 != / <> / IS NOT NULL
1 | -- 大概率失效 |
4. OR 连接的条件有一个没有索引
1 | -- name 有索引,age 没有 → 索引失效 |
5. 隐式类型转换
1 | -- phone 是字符串,你传数字 → 索引失效 |
6. 最左前缀法则不满足(联合索引)
联合索引 (a,b,c)
WHERE a=?✅ 有效WHERE b=?❌ 失效WHERE a=? and c=?✅ 部分有效(只用到 a)
7. ORDER BY / GROUP BY 违反最左前缀
1 | -- 索引 (a,b,c) |
8. MySQL 优化器判断全表扫描更快
数据量少时,MySQL 会自动放弃索引。
9. 使用 NOT IN / NOT EXISTS
1 | WHERE id NOT IN (1,2,3) -- 索引失效 |
三、快速排查索引失效的步骤(工作流程)
- 执行 EXPLAIN,看
key是否为 NULL - 检查是否对索引列运算、函数
- 检查是否**%开头模糊查询**
- 检查类型是否匹配
- 检查联合索引是否满足最左前缀
- 检查是否使用 OR / != / NOT IN
四、一句话总结
- EXPLAIN 看 key=NULL → 索引失效
- 对索引列运算、函数、%开头、类型不匹配、OR、最左前缀不满足 → 90% 索引失效
总结
- 判断索引是否失效:EXPLAIN + 看 key/type
- 最常见失效原因:函数运算、%开头、隐式转换、OR、最左前缀不满足
- 排查按顺序来,10 秒就能定位问题
COUNT(*)和COUNT(1)统计所有行数,包括NULL,而COUNT(列)只统计指定列中非NULL的行数。
使用 EXPLAIN 分析查询只需要在SELECT语句前加上“EXPLAIN”即可。
关注的列有:1.type访问类型;2.rows预估需要扫描的行数;3.keys实际使用的索引;4.extra额外信息;5.possible_keys可能使用的索引;6.id执行顺序;7.select_type查询类型;8.tables查询涉及的表等
SQL 聚合函数包括COUNT、SUM、AVG、MIN、MAX等,用于对数据集进行汇总和统计分析。
WHERE 在分组前过滤原始数据行(不可用聚合函数),HAVING 在分组后过滤分组结果(可用聚合函数),二者执行时机和适用场景有本质差异
EXISTS:检查子查询是否返回至少一行结果,返回布尔值。
IN:检查主查询的值是否在子查询返回的结果集中,返回布尔值。
NOT IN:检查主查询的值是否不在子查询返回的结果集中,返回布尔值。




