MySql-base


[TOC]

MySQL知识点整理

引擎

常用

  • InnoDB,行锁,支持事务、回滚,主流引擎
  • MyISAM老版本5.5-的默认引擎,表锁,不支持事务、回滚,适合大量读取极少数写入场景

了解

  • Archive:行锁,只支持INSERT/SELECT操作,不支持索引,压缩率高,用于存储冷数据如日志、历史订单等,小众方案。业务场景日志一般用Elasticsearch
    ES比较:
  • MEMORY:表锁,基于内存,用于临时表、会话缓存
  • NDB:行锁,基于内存,支持分布式高可用,数据自动分片,适合大规模集群,小众方案。一般业务场景实现用**MyCatShardingSphere +ProxySQL**较多

索引

索引的类型

  • 数据结构分类
    • B+树默认索引方式,多层平衡树,叶子节点双向链表串联存储具体数据,非叶子节点只存储索引
    • 哈希:hash函数获取位置,效率高,但是不支持范围 查询、排序,内存引擎默认使用hash索引
    • 全文:TEXT类型关键字搜索用
    • 空间:基于**R树**,处理坐标等多维数组,支持区域查询、距离计算
  • InnoDB存储方式
    • 聚簇索引:查询无需**回表**,又称为主键索引
      联合主键、单主键
    • 非聚簇索引:二级索引,叶子结点存储索引值及主键值,需要回表二次查询
  • 约束类型、场景
    • 主键索引:唯一、非空,如id
    • 唯一 索引:唯一,允许为空
    • 普通索引:无唯一约束,用于加速查询
    • 联合索引:多列组合形成索引,**最左前缀原则**
    • 全文索引:全文搜索用
    • 空间索引:GIS数据

数据结构

B 树

节点包含数据+子节点指针

B+树

B树的优化版本,非叶子结点只存储主键索引不存储数据,数据全在叶子结点,叶子结点通过双向链表相连,为范围查询提供支撑,MySQL的B+树非叶子结点也有双向链表这是MySQL实现的优化

B+树数据存储量的计算

InnoDB默认页大小为16KB(16384B),固定开销154B,默认预留空间约1230B,真实可用的有效空间以15KB计算。

页物理结构

部分名称 固定占用空间 核心作用 可变
File Header(文件头) 38B 标识页的类型、归属表空间、水平指针等,是页的「身份证」
Page Header(页头) 56B 记录页的内部状态(如页中记录数、B + 树层级、空闲空间位置等)
Infimum + Supremum 26B 页内的「哨兵记录」,标记记录的最小 / 最大值,避免边界判断
User Records(用户记录) 存储真正的业务数据(聚簇索引的行数据、二级索引的 关键字+主键),垂直指针
Free Space(空闲空间) 页内未使用的空间,用于新增记录,空闲空间耗尽会触发页分裂
Page Directory(页目录) >26B 存储用户记录的「槽位指针」,加速页内记录查找
File Trailer(文件尾) 8B 校验页的完整性(防止页损坏)

不同数据类型主键的占用

主键类型 占用字节
TINYINT 1
SMALLINT 2
MEDIUMINT 4
BIGINT 8
CHAR(n) utf8 n*3(utf8),n*4(utf8m64)
VARCHAR(n) 实际长度+1~2
DATE 3
DATETIME 8

假设的存储表

CREATE TABLE tablename (
  id INT PRIMARY KEY,       -- 4 字节
  name VARCHAR(10),         -- 最多 30 字节(10×3)
  age TINYINT,              -- 1 字节
  create_time DATETIME      -- 8 字节
);单条数据43字节,每条记录需要固定开销27字节(事务字段6+回滚指针7+变长字段2+NULL标识位1+记录头11)合计单条数据 占用70字节

计算

  1. 叶子结点可存储数据量:15KB/70B = 214条数据
  2. 非叶子结点存储量,取阶数m = 15KB / (主键大小BIGINT8B + 垂直指针8B)= 937
  3. 三层B+树可存储数据量约为 937^2*214 = 1.8亿的数据量

B*树

B+树的变形,强化了节点的空间利用率,减少分裂次数

  1. 继承B+树的特性,飞叶子节点只存索引,叶子结点存数据+双向链表
  2. 增加兄弟节点指针,非叶子结点也用链表相连,方便节点间数据转移
  3. B+树节点满了会直接分裂,B树节点满了会优先向*兄弟节点借空间,借不到再分裂
  4. 非叶子结点的最小结点树从m/2提升到2m/3,提高空间利用率

R树

区域树

日志

binlog

redolog

undolog

分析、优化

MySQL性能优化步骤

  1. 性能监控、诊断

    • SHOW PROCESSLIST / SHOW FULL PROCESSLIST
    • Performance Schema
    • sys schema(推荐使用)
    • slow query log(慢查询日志)
    • EXPLAIN / EXPLAIN FORMAT=JSON
    • 监控工具:pt-query-digest, Percona Toolkit, Prometheus + Grafana, Zabbix
    -- 查看当前运行的线程
    SHOW PROCESSLIST;
    
    -- 开启慢查询日志(my.cnf 中配置)
    SET GLOBAL slow_query_log = 'ON';
    SET GLOBAL long_query_time = 1; -- 超过1秒记录
    SET GLOBAL log_output = 'TABLE'; -- 或 'FILE'
    
    -- 查看慢查询日志内容(如果输出到表)
    SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;
    
  2. 分析慢SQL

    EXPLAIN SELECT ...
    EXPLAIN FORMAT=JSON SELECT ...
    
    • type: 访问类型(ALL 全表扫描最差,index、range、ref、eq_ref、const 更好)
    • key: 是否命中索引
    • rows: 扫描行数(越少越好)
    • Extra: 是否有 Using filesort, Using temporary 等危险操作
  3. 表索引策略优化、SQL 语句优化

    • 表索引优化,为条件字段建立合理的索引,删减无用索引
    • 避免SELECT * 查询,检查条件索引生效情况
  4. 调整MySQL配置参数

    参数 建议值(示例) 说明
    innodb_buffer_pool_size 物理内存的 70%~80% 缓存数据和索引,最重要
    innodb_log_file_size 1G ~ 2G 提高写性能,减少 checkpoint
    max_connections 500~2000 根据并发连接数调整
    tmp_table_size / max_heap_table_size 64M~256M 内存临时表大小
    sort_buffer_size 2M~4M 每连接排序缓存,不宜过大
    innodb_flush_log_at_trx_commit 1(安全),2(折中),0(快但不安全) 控制事务持久性
    query_cache_type 0(关闭) MySQL 8.0 已移除,5.7 可关闭
  5. 表结构、存储引擎优化

  6. 读写分离、分库分表、前置redis、消息队列、本地缓存等

事务的异常情况分析//TODO

三方组件、工具

ElasticSearch

MyCat

ShardingSphere

ProxySQL

常见问题、术语定义

术语定义

B+树的术语定义

节点存储的内容

关键字(key):用于排序、查找的和核心值,是索引的标识
主键索引:特殊关键字,对应主键字段如ID,是聚簇索引的核心关键字
指针:内存/磁盘地址的引用,B+树分为子节点指针数据指针

回表

回表指的是二级索引需要通过主键索引二次查询获取其他字段,因为B+树非叶子结点只存储主键和指针

联合主键、单主键

一个主键多个字段 = 联合主键;
单主键 = 单字段

阶数m

阶数 -1 <= 可用空间 /索引关键字大小
叶子结点可存储数据量 = (叶大小-固定开销)/单条数据大小

最左前缀原则

查询索必须从左到右匹配,第一个条件非索引字段会直接扫全表
[索引失效有哪些情况](#5. 索引失效的情形有哪些?)

事务 //TODO

事务是数据库操作的一个逻辑单元,由一组SQL语句组成,要么全部执行,要么全部回滚,保证数据的一致性和完整性

事务的特性ACID

  • Atomicity:原子性,不可分割,要么全做要么全部做
  • Consistency:一致性,事务执行前后数据库从一个一致状态转移到另一个一致状态
  • Isolation:隔离性,多事务并发执行,彼此互不干扰
  • Durability:持久性,一旦事务提交,对数据库的修改是永久性的,即便系统崩溃也不会丢失

事务的隔离级别

名称 优点 问题
读未提交 极致的性能优先 可靠性极差
读已提交 不可重复读、幻读
可重复读 幻读、间隙锁容易引发死锁增加运维成本
串行读 串行解决所有并发问题 无并发能力

MVCC是什么

锁 //TODO

常见问题

1. MySQL为什么选择B+树作为索引结构,没有选择B*树?

B树因为节点存储数据,导致节点的存储效率低(单节点存储的关键字数量远小于只存关键字),树高会更高,磁盘IO会更多;并且B树的范围查询性能极差,节点相互独立,范围查询需要多次回溯、遍历不同分支,效率低下。B树更适合内存数据库,在内存中IO开销几乎可以忽略

B+树是多叉树,树矮检索3层B+树就可以存储近2000w数据(如何计算一棵树能存储多少数据);
非叶子结点只存储key和指针,节省空间(点查询劣于B树,范围查询优于B树)
叶子结点、非叶子结点双向链表串联,方便范围查询、寻址

B*树的出现是为了提高节点的空间利用率,[节点填充率](#3. B+树是节点满了之后会分裂,所谓的最小填充率1/2是什么意思?)2/3,并不是节点填充率越高越好;在节点满的时候不会直接分裂而是会先遍历兄弟节点、判断、移动数据,而这个操作的时间成本远大于B+树节点分裂的时间,在时间和空间的倾向上,B*树更倾向于空间,而B+树则在空间和时间的选择上更均衡。

2. 如何计算一棵树能存储多少数据

根据不同索引不同的计算方式
聚簇索引:单条数据*阶层m^(树高n-1)
非聚簇索引:(二级索引+主键索引)*阶层m^(树高n-1)

参考B+树

3. B+树是节点满了之后会分裂,所谓的最小填充率1/2是什么意思?

填充率是一个节点的存储红线,它存在的目的是为了防止节点过于稀疏,避免树高膨胀。如果小于这个存储阈值,就会触发节点合并。

节点填充率越高,空间利用率越高,节点的合并、数据迁移 触发概率更高;
填充率越低,节点越松散,合并、迁移概率越低

4. 联合主键和多主键的区别

在关系型数据库中多主键是不存在的,联合主键的含义是一个主键

5. 索引失效的情形有哪些?

  1. 函数包裹索引字段会使索引失效,隐式类型转换其实进行了CAST函数强制转换

  2. 使用!= 或 <> 、NOT IN 或者 NOT EXISTS、IS NOT NULL等取反操作通常无法有效利用索引

    B+树是有序的单向区间索引,优化器是成本优先原则,而!=是筛选出除了某个值之外的所有数据,B+树天生不擅长查反向、离散的全集

    假设强制走索引,取非值,首先要在索引查询<x;再索引查询>x;再合并去重;最后拿着所有id批量回表走聚簇索引。这个成本是2次完整的B+树索引+内存合并计算+回表聚簇索引,成本远高于1次磁盘舒徐IO

  3. OR 连接任意两个字段都会使索引 失效

    两个索引用or相连,如果要走索引他会先走A索引的B+树,拿到主键id;再走B索引的B+树拿到主键id;两次查询的主键id去重合并;再回表走聚簇索引查业务数据。

    这个过程包含2次B+树查询+内存去重+批量回表,效率远低于全表扫描,MySQL的优化器会判定全表扫描更划算,放弃两个单列索引

    只有在两个字段是联合索引的情况下OR才会索引生效

  4. 模糊匹配%开头违背最左前缀原则,索引失效

  5. 数据量过小或索引选择性差

  6. 索引字段参与运算

  7. SQL查询不规范 如SELECT * 会强制回表,当回表代价过高时索引效率降低

6. MySQL默认的事务默认隔离级别是什么?为什么选择它

7. 什么是快照读、当前读?

8. 如何解决脏读、不可重复读、幻读的情况?什么是


文章作者: LoaderLand
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LoaderLand !
  目录