数据库进阶

一、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 及以上默认)
  • 性格:稳重靠谱、安全第一,啥活都能干,尤其擅长复杂业务。

  • 核心技能

    1. 支持 "事务"(比如转账时,扣钱和加钱要么一起成,要么一起失败,不会出问题);

    2. 支持 "行级锁"(多人同时改不同数据不冲突,比如电商平台多人下单不卡);

    3. 支持 "外键(foreign key)"(比如订单表必须关联用户表,不会出现 "没有用户的订单");

    4. 崩溃恢复(服务器断电也不怕,重启后数据能恢复)。

  • 适用场景:绝大多数业务系统(电商、支付、管理系统等),只要涉及数据安全和并发操作,选它准没错!

2. MyISAM:"快手管家"(老版本默认,现在少用)
  • 性格:干活快、不墨迹,但有点 "不靠谱",只适合简单活。

  • 核心技能

    1. 读写速度比 InnoDB 快(因为不做事务、锁这些 "额外工作");

    2. 占用磁盘空间小(数据存储更紧凑)。

  • 缺点

    1. 不支持事务、外键;

    2. 只支持 "表级锁"(多人同时改一张表会排队,并发差);

    3. 崩溃后数据可能丢失(没有恢复机制)。

  • 适用场景:静态数据、只读场景(比如博客文章、新闻列表、日志归档,只查不改或很少改)

3. Memory:"临时管家"(内存型引擎)
  • 性格:速度飞起来,但健忘(重启就忘)。

  • 核心技能:数据全存在内存里,查询、修改速度极快(比磁盘快几百倍)。

  • 缺点

    1. 服务器重启 / 断电,数据直接消失;

    2. 不支持事务,数据量不能太大(受内存大小限制)。

  • 适用场景:临时计算、缓存数据(比如临时统计报表、会话缓存,用完就扔的那种)。

四、存储引擎的选择

场景描述 选哪个引擎?
电商下单、支付、用户管理(要安全、要并发) InnoDB(必选)
博客文章、新闻列表(只看不改,要快) MyISAM
临时统计数据、会话缓存(用完就扔,要极速) Memory

索引

是帮助 MySQL 高效获取数据 的 数据结构 (有序),索引其实就是数据库表的 "字典目录"------ 就像查字典不用从头翻到尾,先看目录找页码再翻页,数据库查数据也不用扫描全表,靠索引直接定位到要找的行,速度能快几十上百倍。比如查 "id=100 的用户",有索引 1 毫秒就能找到,没索引可能要翻几万行数据。

索引的核心作用(就 2 个)
  1. 加速查询 :这是最核心的!比如查询 SELECT * FROM user WHERE id=100,有索引的话,1 毫秒就能找到;没索引的话,可能要扫描几万行数据,慢几十倍。

  2. 优化排序 :比如查询 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 字段)。

  • 通俗理解:字典的 "唯一页码",每个页码对应唯一的词条,绝对不会重复。

  • 建表时直接指定:

    sql 复制代码
    CREATE TABLE user (
      id INT PRIMARY KEY, -- 主键索引,自动创建
      name VARCHAR(50)
    );
常规索引(INDEX):"普通目录页"
  • 特点 :可以有多个,字段值可以重复、可以为 NULL(比如 user 表的 namephone 字段)。

  • 通俗理解:字典的 "拼音目录",多个词条可能拼音相同(比如 "李" 和 "理"),可以重复。

  • 建表后添加:

    复制代码
    -- 给 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)。

简单说:这种结构让查询 "又快又稳",不管查哪个数据,都要走差不多的步骤,不会出现 "有时候快有时候慢" 的情况。

索引怎么用?
  1. 建表时给主键(id)加主键索引(自动加,不用手动);

  2. 给经常查询、排序的字段加普通索引;

  3. 给需要唯一约束的字段(手机号、邮箱)加唯一索引;

  4. 别乱加索引,够用就行!

日常开发中,只要记住 "索引 = 字典目录",就知道什么时候该加、什么时候不该加啦~

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 个关键点,通俗说:

  1. 先 "打开记录仪":开启慢查询日志功能(默认是关的,需要手动开);

  2. 设 "触发条件":比如设定 "执行超过 2 秒的 SQL 就记录";

  3. 看 "记录报告":从日志文件里找慢 SQL,针对性优化(比如加索引、简化 SQL)。

简单总结:慢查询日志就是帮你抓 "拖后腿的 SQL" 的工具,有了它,不用瞎猜哪条 SQL 慢,直接看日志就知道该优化啥~

profile详细

Profile 就是 MySQL 里给 SQL 做 "精准计时" 的工具 ------ 像给 SQL 装了个秒表,把它执行的每一步(比如解析语法、查索引、读数据、排序)都拆开来,告诉你每步花了多少时间,精准找到 "慢在哪",比慢查询日志更细。

核心用法
  1. 查询profile: select @@have_profiling; //查询当前是否有profile操作

  2. 开开关:SET profiling = ON/1;(临时生效,关了终端就没了)

  3. 跑 SQL:执行你要分析的语句(比如 SELECT * FROM order WHERE user_id=123;

  4. 看结果:

  • 先看所有记录的 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 查找数据的 "方式"(效率从高到低) 出现 refrange(走索引) 出现 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 BYGROUP BY 没用到索引,需要给排序 / 分组字段加索引,比如给 create_time 加索引,就能消除这两个提示。

一句话总结

EXPLAIN 是 "SQL 体检工具"------ 写好 SQL 后先跑一遍 EXPLAIN,只要 type 不是 ALL、key 不为 NULL、rows 不大,这条 SQL 基本就高效;反之就针对性加索引、改查询条件,不用等上线才发现慢!

相关推荐
Pocker_Spades_A5 小时前
时序数据库选型指南:用工程视角理解 Apache IoTDB
数据库·apache·时序数据库·iotdb
心动啊1215 小时前
MySQL在python中的使用——连接方式及对对象的调用
数据库·mysql
橘颂TA5 小时前
【Linux】不允许你还不会——信号保存(3)
linux·服务器·网络·数据库
Chloeis Syntax5 小时前
MySQL初阶学习日记(6)--- 索引
数据库·学习·mysql
0和1的舞者5 小时前
《MyBatis 从入门到上手:超全基础操作 + XML 配置指南》
数据库·spring boot·学习·spring·mybatis·框架·开发
jarreyer5 小时前
mysql常见指标计算笔记
数据库·mysql
源代码•宸5 小时前
goframe框架签到系统项目(安装 redis )
服务器·数据库·经验分享·redis·后端·缓存·golang
5 小时前
TIDB——TIKV——分布式事务与MVCC
数据库·分布式·tidb·分布式数据库·tikv·
5 小时前
TIDB——TIKV——RocksDB
数据库·分布式·tidb·分布式数据库·