Mysql存储引擎

Mysql存储引擎 InnoDB和MyISAM引擎对比 InnoDB如何组织数据 主索引(聚簇索引)将数据存储在叶子节点,辅助索引存储指向主键的指针 一行数据是如何储存的? 一条sql语句如何执行 语句中每个字段的执行顺序 # 什么是存储过程? **存储过程(Stored Procedure)** 是**数据库中预先编译好、存储在服务器上的一组 SQL 语句集合**,你可以把它理解成**数据库里的“自定义函数/小程序”**。

它提前把复杂的 SQL 逻辑(增删改查、循环、判断、事务等)写好并保存,需要使用时,直接调用名字就能执行,不用重复写代码。


一、用最简单的比喻理解

你要做一道菜:

  • 普通 SQL:每次都把所有食材、步骤写一遍,一步步操作;
  • 存储过程:把完整菜谱提前存在厨房,想吃的时候喊一声菜名,厨师直接按菜谱做好。

二、核心特点

  1. 存储在数据库服务器
    不是写在你的代码里,而是保存在 MySQL、Oracle、SQL Server 等数据库中。
  2. 预先编译
    第一次执行后就编译好了,后续调用速度更快
  3. 可重复调用
    一次编写,无数次使用,程序、报表、脚本都能直接调用。
  4. 支持参数、逻辑判断、循环
    能实现复杂业务逻辑,不只是简单查询。
  5. 减少网络传输
    不用把一大段 SQL 发给服务器,只发一个调用指令。

三、一个极简示例(MySQL)

1. 创建一个简单的存储过程

1
2
3
4
5
6
7
8
-- 创建存储过程:根据用户ID查询用户名
DELIMITER // -- 临时修改语句结束符
CREATE PROCEDURE GetUserName(IN user_id INT, OUT user_name VARCHAR(50))
BEGIN
-- 执行查询,把结果赋值给输出参数
SELECT name INTO user_name FROM users WHERE id = user_id;
END //
DELIMITER ; -- 恢复结束符

2. 调用存储过程

1
2
3
-- 调用:传入ID=1,返回用户名
CALL GetUserName(1, @name);
SELECT @name;

3. 说明

  • IN:输入参数(你传给存储过程的值)
  • OUT:输出参数(存储过程返回给你的结果)
  • 调用时只用 CALL 存储过程名(参数),非常简洁

四、为什么要用存储过程?(优点)

  1. 提高执行速度
    预编译,避免重复解析 SQL。
  2. 减少网络流量
    只传调用指令,不传整段 SQL。
  3. 代码复用,便于维护
    逻辑统一修改,不用到处改代码。
  4. 安全可控
    可以给用户分配执行存储过程的权限,不直接开放表权限。
  5. 适合复杂业务
    支持事务、循环、条件判断,能处理复杂逻辑。

五、缺点(也要知道)

  1. 不同数据库语法不通用(MySQL 写的不能直接在 Oracle 用);
  2. 调试比普通代码麻烦;
  3. 过多复杂存储过程会加重数据库服务器负担。

总结

  1. 存储过程 = 数据库里的预编译 SQL 程序
  2. 一次编写,反复调用,高效、安全、简洁
  3. 适合复杂、频繁执行的数据库逻辑
  4. 主流数据库(MySQL、Oracle、SQL Server)都支持
如何实现数据库不停服迁移 INT(11)表示什么 CHAR和VARCHAR Decimal和float&double 时间 datetime:不受时区影响,绝对时间,占8个字节,手动更新 timestamp:受时区影响,相对时间,占4个字节,自动更新 在 MySQL 中,Boolean 类型通常用TINYINT(1)表示,Boolean并不是一个真实存在的引擎 # MySQL 存文章:别用 BLOB,TEXT 完全可以用! 先给你一个**最直接、最实用的结论**: **存文章、长文本,MySQL 首选 `TEXT` 系列类型,完全没问题,根本不用避开!**

“不推荐 TEXT/BLOB”,是有前提条件


一、先辟谣:为什么有人说“不推荐 TEXT/BLOB”?

他们说的坑,主要是这 3 点:

  1. 临时表不能放内存:查询如果用到 TEXT/BLOB,MySQL 只能用磁盘临时表,比内存慢
  2. 行溢出:大文本会让数据行跨页存储,读取整行时变慢
  3. 索引限制:不能直接给 TEXT 建全索引,只能建前缀索引

但!这些问题对「存文章」几乎不影响!
文章是一次写入、多次读取、很少修改的场景,完全适配 TEXT。


二、存文章,MySQL 官方推荐的类型

按文章长度从小到大选,直接套用:

类型 最大容量 适用场景
TINYTEXT 255 字符 简介、摘要、小标题
TEXT 64KB 短篇文章、博客、笔记(最常用)
MEDIUMTEXT 16MB 长文、小说、文档
LONGTEXT 4GB 超大内容(一般不用)

日常写博客、文章、内容:直接用 TEXT 就够了
超长文章:用 MEDIUMTEXT


三、真正正确的存储方案(生产环境通用)

1. 最佳表结构设计

1
2
3
4
5
6
7
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL, -- 短字符串用 VARCHAR
content TEXT NOT NULL, -- 文章正文用 TEXT
create_time DATETIME NOT NULL,
INDEX idx_create_time (create_time)
);

2. 关键优化(解决 TEXT 的小缺点)

  1. 不要把 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=?;
  2. 常用字段和 TEXT 字段分离
    列表高频字段放主表,大文本放副表(垂直拆分),性能起飞。

  3. 不要给 content 建索引
    文章全文搜索用 ES/Meilisearch,别用 MySQL 索引。


四、那 BLOB 什么时候用?永远别存文章!

BLOB二进制类型,用来存:

  • 图片
  • 文件
  • 音频视频

存文本绝对不要用 BLOB

  • 不支持字符集
  • 不支持排序、模糊查询
  • 占空间更大
  • 读取性能更差

五、终极总结(一句话记住)

  • 存文章/长文本 → 用 TEXT / MEDIUMTEXT(完全推荐)
  • 存文件/图片 → 用 BLOB(但更推荐存路径,文件放磁盘/OSS)
  • VARCHAR 只存短文本(标题、昵称)

总结

  1. TEXT 是存文章的标准方案,放心大胆用
  2. 所谓“不推荐 TEXT”是针对高频更新、超大表的特殊场景
  3. 文章内容 = TEXT / MEDIUMTEXT,标题 = VARCHAR,文件 = 存路径
  4. 只要不 SELECT *,性能完全没问题
定点数存金融相关 VarBinary

数据库视图是基于一个或多个表的查询结果创建的虚拟表,用于简化复杂查询、提高数据安全性和提供数据抽象。

数据库游标是一种数据库对象,用于逐行处理查询结果集,允许在结果集中进行遍历、检索、更新和删除操作,适合需要逐行处理数据的场景。

为什么要对象存储

数据库三大范式

数据库的三大范式是:

  • 第一范式(1NF):确保每列的值都是不可分割的原子值。
  • 第二范式(2NF):在满足第一范式的基础上,确保每个非主属性完全依赖于主键。
  • 第三范式(3NF):在满足第二范式的基础上,确保每个非主属性不传递依赖于主键。

hash索引和b+树索引

Hash索引是基于键值对的,通过键的哈希值直接查询存储的指。而BTree是根据索引字段值的大小关系去有序存储,BTree的查询是不断缩小查找范围,最终得到查找的数据。两者相比,hash的查找速度更快,但是也没有快很多,这也看BTree层数的高度和数据量的大小,但是BTree更适合范围查找,通过数据的有序性,查询某一段区间的数据会更快。
B+ 树的叶子节点按顺序链接,支持快速的范围查询。
B+ 树节点大小与磁盘一次读取的最小单位(磁盘页)大小匹配,减少磁盘 I/O 操作。
三层B+树能存多少数据?

如何判断 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
3
-- 失效
WHERE YEAR(create_time) = 2025
WHERE age + 1 = 20

2. 模糊查询以 % 开头

1
2
-- 失效
WHERE name LIKE '%张三'

3. 使用 != / <> / IS NOT NULL

1
2
-- 大概率失效
WHERE name != '张三'

4. OR 连接的条件有一个没有索引

1
2
-- name 有索引,age 没有 → 索引失效
WHERE name = 'a' OR age = 20

5. 隐式类型转换

1
2
-- phone 是字符串,你传数字 → 索引失效
WHERE phone = 13800138000

6. 最左前缀法则不满足(联合索引)

联合索引 (a,b,c)

  • WHERE a=? ✅ 有效
  • WHERE b=? ❌ 失效
  • WHERE a=? and c=? ✅ 部分有效(只用到 a)

7. ORDER BY / GROUP BY 违反最左前缀

1
2
3
-- 索引 (a,b,c)
ORDER BY c ❌ 失效
ORDER BY a,b ✅ 有效

8. MySQL 优化器判断全表扫描更快

数据量少时,MySQL 会自动放弃索引。

9. 使用 NOT IN / NOT EXISTS

1
WHERE id NOT IN (1,2,3)  -- 索引失效

三、快速排查索引失效的步骤(工作流程)

  1. 执行 EXPLAIN,看 key 是否为 NULL
  2. 检查是否对索引列运算、函数
  3. 检查是否**%开头模糊查询**
  4. 检查类型是否匹配
  5. 检查联合索引是否满足最左前缀
  6. 检查是否使用 OR / != / NOT IN

四、一句话总结

  • EXPLAIN 看 key=NULL → 索引失效
  • 对索引列运算、函数、%开头、类型不匹配、OR、最左前缀不满足 → 90% 索引失效

总结

  1. 判断索引是否失效:EXPLAIN + 看 key/type
  2. 最常见失效原因:函数运算、%开头、隐式转换、OR、最左前缀不满足
  3. 排查按顺序来,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:检查主查询的值是否不在子查询返回的结果集中,返回布尔值。