一、MySQL体系结构
连接层、服务层、引擎层、存储层
连接层 = 超市大门 + 收银员
-
作用:负责接待 "顾客"(客户端,比如 Workbench、你的 Java 程序),验证身份(核对用户名密码),给顾客分配 "购物车"(数据库连接)。
-
通俗举例:你进超市要先过门禁,收银员确认你是合法顾客,然后给你推车,你才能开始逛。没有这一步,你连超市门都进不去。
2. 服务层 = 超市导购员 + 调度中心
-
作用:帮你规划 "购物路线"(优化 SQL 执行计划),告诉你东西在哪(解析 SQL 语法),核对你有没有买东西的权限(权限校验),最后帮你整理买好的商品(处理查询结果)。
-
通俗举例 :你说 "我要买牛奶和面包",导购员直接带你去乳制品区和烘焙区,不会让你瞎逛;同时确认你带了钱(有权限),最后帮你把东西装袋。所有 "动脑子" 的活都在这一层。
3. 引擎层 = 超市货架管理员
-
作用:负责具体的 "货位管理"(数据存储和读取),不同货架有不同的摆放规则(对应不同存储引擎)。比如有的货架(InnoDB)支持 "退货换货"(事务、行锁),有的货架(MyISAM)只卖特价商品,不支持退换(适合只读场景)。
-
通俗举例:导购员让货架管理员拿牛奶,管理员就从自己负责的货架上取货,他不管你怎么进来的、买了多少,只负责 "存取货" 这个动作。
4. 存储层 = 超市仓库
-
作用 :货架上的货最终都来自仓库,仓库就是数据的最终存放地(磁盘文件)。货架管理员需要货了,就去仓库取;卖不完的货,再放回仓库存起来。
-
通俗举例:仓库里整箱的牛奶、成捆的面包,就是最原始的 "数据",货架只是临时展示用的,真正的存货都在仓库里。
二、存储引擎简介
存储引擎就是存储数据,建立索引、更新、查询数据等技术的实现方式。存储引擎是基于表的,而不得基于库的,所以存储引擎也可被称为表类型。
在创建表时指定存储引擎
sql
show engines; //查看当前数据库支持的存储引擎
-- 建一个电商订单表,用 InnoDB(支持事务)
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
money DECIMAL(10,2)
) ENGINE=InnoDB; //默认就是这个所以可以不写
-- 建一个博客文章表,用 MyISAM(只读快)
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(200),
content TEXT
) ENGINE=MyISAM;
三、存储引擎的特点
1. InnoDB:"全能管家"(MySQL 5.5 及以上默认)
-
性格:稳重靠谱、安全第一,啥活都能干,尤其擅长复杂业务。
-
核心技能
-
支持 "事务"(比如转账时,扣钱和加钱要么一起成,要么一起失败,不会出问题);
-
支持 "行级锁"(多人同时改不同数据不冲突,比如电商平台多人下单不卡);
-
支持 "外键(foreign key)"(比如订单表必须关联用户表,不会出现 "没有用户的订单");
-
崩溃恢复(服务器断电也不怕,重启后数据能恢复)。
-
-
适用场景:绝大多数业务系统(电商、支付、管理系统等),只要涉及数据安全和并发操作,选它准没错!
2. MyISAM:"快手管家"(老版本默认,现在少用)
-
性格:干活快、不墨迹,但有点 "不靠谱",只适合简单活。
-
核心技能
-
读写速度比 InnoDB 快(因为不做事务、锁这些 "额外工作");
-
占用磁盘空间小(数据存储更紧凑)。
-
-
缺点
-
不支持事务、外键;
-
只支持 "表级锁"(多人同时改一张表会排队,并发差);
-
崩溃后数据可能丢失(没有恢复机制)。
-
-
适用场景:静态数据、只读场景(比如博客文章、新闻列表、日志归档,只查不改或很少改)
3. Memory:"临时管家"(内存型引擎)
-
性格:速度飞起来,但健忘(重启就忘)。
-
核心技能:数据全存在内存里,查询、修改速度极快(比磁盘快几百倍)。
-
缺点
-
服务器重启 / 断电,数据直接消失;
-
不支持事务,数据量不能太大(受内存大小限制)。
-
-
适用场景:临时计算、缓存数据(比如临时统计报表、会话缓存,用完就扔的那种)。
四、存储引擎的选择
| 场景描述 | 选哪个引擎? |
|---|---|
| 电商下单、支付、用户管理(要安全、要并发) | InnoDB(必选) |
| 博客文章、新闻列表(只看不改,要快) | MyISAM |
| 临时统计数据、会话缓存(用完就扔,要极速) | Memory |
索引
是帮助 MySQL 高效获取数据 的 数据结构 (有序),索引其实就是数据库表的 "字典目录"------ 就像查字典不用从头翻到尾,先看目录找页码再翻页,数据库查数据也不用扫描全表,靠索引直接定位到要找的行,速度能快几十上百倍。比如查 "id=100 的用户",有索引 1 毫秒就能找到,没索引可能要翻几万行数据。
索引的核心作用(就 2 个)
-
加速查询 :这是最核心的!比如查询
SELECT * FROM user WHERE id=100,有索引的话,1 毫秒就能找到;没索引的话,可能要扫描几万行数据,慢几十倍。 -
优化排序 :比如查询
SELECT * FROM user ORDER BY name,有name字段的索引,MySQL 直接用索引的有序结构排序,不用额外做 "排序操作",效率更高。
索引分类
聚集索引:索引 = 数据,查一次就到位,速度最快(默认主键就是);
二级索引:索引 = 主键,查两次才拿到完整数据,速度比聚集索引慢一点(先查到主键再去聚集索引查),但灵活(可以给多个字段加)。
索引语法
sql
create [unique|fulltext]index index_name on table_name (index_Tname,); //创建索引
show index from table_name; //查看索引
drop index index_name on table_name; //删除索引
主键索引(PRIMARY KEY):"唯一的目录页"
-
特点 :每个表只能有 1 个,字段值必须唯一(不能重复),且不能为
NULL(比如user表的id字段)。 -
通俗理解:字典的 "唯一页码",每个页码对应唯一的词条,绝对不会重复。
-
建表时直接指定:
sqlCREATE TABLE user ( id INT PRIMARY KEY, -- 主键索引,自动创建 name VARCHAR(50) );
常规索引(INDEX):"普通目录页"
-
特点 :可以有多个,字段值可以重复、可以为
NULL(比如user表的name、phone字段)。 -
通俗理解:字典的 "拼音目录",多个词条可能拼音相同(比如 "李" 和 "理"),可以重复。
-
建表后添加:
-- 给 name 字段加普通索引 CREATE INDEX idx_user_name ON user(name);
3. 唯一索引(UNIQUE):"不重复的普通目录"
-
特点 :可以有多个,但字段值必须唯一(不能重复),可以为
NULL(比如user表的phone字段,手机号不能重复)。 -
通俗理解:字典的 "身份证号目录",每个身份证号对应唯一的人,不能重复,但可以有空缺(比如有人没提供)。
-
用法
-- 给 phone 字段加唯一索引(防止重复手机号) CREATE UNIQUE INDEX idx_user_phone ON user(phone);
五、InnoDB 的索引核心:B + 树结构
InnoDB 用的是 B + 树 做索引(就像一棵 "倒过来的树"),特点是:
-
叶子节点(最底层)存的是实际数据(或数据地址),查询时只需要遍历到叶子节点,效率稳定;
-
所有数据都在叶子节点,且叶子节点之间是 "链表" 结构(双向链表),方便范围查询(比如
WHERE id BETWEEN 100 AND 200)。
简单说:这种结构让查询 "又快又稳",不管查哪个数据,都要走差不多的步骤,不会出现 "有时候快有时候慢" 的情况。
索引怎么用?
-
建表时给主键(
id)加主键索引(自动加,不用手动); -
给经常查询、排序的字段加普通索引;
-
给需要唯一约束的字段(手机号、邮箱)加唯一索引;
-
别乱加索引,够用就行!
日常开发中,只要记住 "索引 = 字典目录",就知道什么时候该加、什么时候不该加啦~
SQL性能分析
show global status like 'com_______'; //查看当前数据库增删改查的访问次数
慢查询日志
慢查询日志就是 MySQL 的 "慢动作记录仪"------ 专门盯着所有执行的 SQL 语句,只要某条 SQL 执行时间超过你设定的 "阈值"(默认是 10 秒,实际开发中一般设 1~3 秒),就把这条 SQL 的 "作案细节"(执行时间、执行用户、执行时间点、SQL 语句本身)记下来,方便你后续排查 "谁拖慢了数据库"。
举个例子:你做电商网站,用户反映 "下单要等 5 秒",打开慢查询日志一看,发现 SELECT * FROM order WHERE user_id=123 这条 SQL 执行了 4.8 秒,超过了你设的 3 秒阈值,日志里还记着它没走索引、扫描了 10 万行数据 ------ 这就找到 "罪魁祸首" 了,接下来只要给 user_id 加个索引,就能提速。
核心用法就 3 个关键点,通俗说:
-
先 "打开记录仪":开启慢查询日志功能(默认是关的,需要手动开);
-
设 "触发条件":比如设定 "执行超过 2 秒的 SQL 就记录";
-
看 "记录报告":从日志文件里找慢 SQL,针对性优化(比如加索引、简化 SQL)。
简单总结:慢查询日志就是帮你抓 "拖后腿的 SQL" 的工具,有了它,不用瞎猜哪条 SQL 慢,直接看日志就知道该优化啥~
profile详细
Profile 就是 MySQL 里给 SQL 做 "精准计时" 的工具 ------ 像给 SQL 装了个秒表,把它执行的每一步(比如解析语法、查索引、读数据、排序)都拆开来,告诉你每步花了多少时间,精准找到 "慢在哪",比慢查询日志更细。
核心用法
-
查询profile: select @@have_profiling; //查询当前是否有profile操作
-
开开关:
SET profiling = ON/1;(临时生效,关了终端就没了) -
跑 SQL:执行你要分析的语句(比如
SELECT * FROM order WHERE user_id=123;) -
看结果:
-
先看所有记录的 SQL:
SHOW PROFILES;(拿到要分析的 SQL 编号,比如 Query_ID=1) -
再看详细步骤耗时:
SHOW PROFILE FOR QUERY 1;(把 1 换成你的 Query_ID)
关键看什么?
结果里会列一堆步骤,重点盯耗时最长的:
-
比如 "Retrieving Data"(读数据)久→索引没建好,加索引;
-
"Sorting Result"(排序)久→排序字段没加索引;
-
"Copying to tmp table"(临时表)久→分组 / 连接逻辑要优化。
慢查询日志告诉你 "哪条 SQL 慢",Profile 告诉你 "这条 SQL 慢在哪个步骤",优化时精准下手,不用瞎改
explain执行计划
EXPLAIN 就是 MySQL 的 "SQL 执行计划预览器" ------ 不用真的执行 SQL,就能提前看到 MySQL 会怎么执行这条 SQL(比如走不走索引、扫描多少行数据、用什么连接方式),帮你预判 SQL 有没有效率问题,从源头避免慢查询。
核心用法
在你要分析的 SQL 前面加 EXPLAIN 就行,比如:
sql
-- 原SQL:查询用户订单
SELECT * FROM order WHERE user_id=123 ORDER BY create_time;
-- 加EXPLAIN查看执行计划
EXPLAIN SELECT * FROM order WHERE user_id=123 ORDER BY create_time;
执行后会返回一张 "执行计划表",不用看复杂字段,盯 3 个核心信息就够了!
重点看 3 列
| 列名 | 通俗含义 | 好情况 | 坏情况 |
|---|---|---|---|
| type | MySQL 查找数据的 "方式"(效率从高到低) | 出现 ref 或 range(走索引) |
出现 ALL(全表扫描,没走索引) |
| key | 实际用到的索引名称 | 显示你建的索引(比如 idx_user_id) |
显示 NULL(没用到任何索引) |
| rows | MySQL 预估要扫描的行数 | 数字越小越好(比如几十、几百) | 数字极大(比如几万、几十万,扫全表) |
例子 1:好的执行计划
type=ref,key=idx_user_id,rows=50→ 解读:MySQL 走了 user_id 的索引,只需要扫 50 行就能找到数据,效率高!
例子 2:坏的执行计划
type=ALL,key=NULL,rows=100000→ 解读:MySQL 没走任何索引,要扫描 10 万行数据(全表扫),肯定慢!优化方向:给 user_id 加索引。
如果 Extra 列出现 Using filesort(文件排序)或 Using temporary(临时表),说明 SQL 里的 ORDER BY 或 GROUP BY 没用到索引,需要给排序 / 分组字段加索引,比如给 create_time 加索引,就能消除这两个提示。
一句话总结
EXPLAIN 是 "SQL 体检工具"------ 写好 SQL 后先跑一遍 EXPLAIN,只要 type 不是 ALL、key 不为 NULL、rows 不大,这条 SQL 基本就高效;反之就针对性加索引、改查询条件,不用等上线才发现慢!