MySQL
事务的ACID特性
原子性 (Atomicity)
- 事务是最小执行单元,全部成功或全部失败
- 通过
Undo Log实现回滚
一致性 (Consistency)
- 事务前后数据库保持合法状态
- 由应用层和数据库约束共同保证
隔离性 (Isolation)
- 事务间操作相互隔离
- 通过锁和
MVCC机制实现
持久性 (Durability)
- 事务提交后数据永久保存
- 通过
Redo Log和刷盘策略保证
隔离级别
读未提交 (RU)
- 可能脏读、不可重复读、幻读
读已提交 (RC)
- 解决脏读,但可能出现不可重复读和幻读(默认隔离级别)
可重复读 (RR)
- 解决脏读、不可重复读(MySQL默认级别,通过
MVCC+Next-Key Locks避免幻读)
串行化 (Serializable)
- 完全隔离,性能最低
MVCC(多版本并发控制)
核心概念
- 通过快照读实现非阻塞读,解决读写冲突
实现机制
- 每行数据包含隐藏字段
DB_TRX_ID(事务ID)和DB_ROLL_PTR(回滚指针) - 通过
Undo Log构建版本链,结合ReadView判断数据可见性 - 只在
RC和RR隔离级别下生效
InnoDB的索引结构
B+树索引
- 非叶子节点只存键值,叶子节点存储数据(聚集索引存整行,二级索引存主键)
B+树相比B树的优势
- 叶子节点形成有序链表,范围查询高效
- 非叶子节点存储更多键,树高更低,减少IO次数
- 数据只存在叶子节点,查询稳定性更高
死锁
产生条件
- 互斥、请求与保持、不可剥夺、循环等待
检测
- 通过
等待图 (Wait-for Graph)检测循环依赖,触发死锁回滚
避免方案
- 事务按固定顺序访问资源
- 降低事务粒度,减少锁竞争
- 设置合理的事务超时时间(
innodb_lock_wait_timeout) - 使用
SELECT ... FOR UPDATE NOWAIT(MySQL 8.0+)
慢查询优化
1. 定位慢SQL
开启 slow_query_log,分析慢日志
2. Explain分析
关注 type(扫描方式)、key(使用索引)、rows(扫描行数)、Extra(是否 Using filesort / Using temporary)
3. 优化方向
- 添加缺失索引,避免全表扫描
- 优化SQL写法(如拆分复杂查询、避免
SELECT *) - 使用覆盖索引,减少回表操作
- 调整表结构(如范式化/反范式化)
主从复制
原理
- 主库通过
Binlog记录变更,从库通过I/O线程拉取日志,SQL线程重放
延迟解决
- 并行复制(
MTS,基于库/组提交/事务粒度) - 调整
sync_binlog和innodb_flush_log_at_trx_commit参数平衡安全与性能 - 使用半同步复制(
semisync)确保主从数据一致性
分库分表
垂直拆分
- 按业务拆分(如订单库、用户库)
- 优点:解耦业务,降低单库压力
- 缺点:无法解决单表数据量过大的问题
水平拆分
- 按规则分散数据(如按ID取模、按时间范围)
- 优点:解决单表数据膨胀问题
- 缺点:跨分片查询复杂,事务管理困难
代理层 vs 客户端分片
- ShardingSphere、MyCAT等工具实现
Explain关键字
Using index
- 仅用索引即可返回所需数据(覆盖索引)
Using index condition
- 使用索引条件下推(ICP),在存储引擎层过滤数据,减少回表次数
覆盖索引
定义
- 查询的字段全部被索引覆盖,无需回表
示例
-- 创建索引 (age, name)
CREATE INDEX idx_age_name ON user(age, name);
-- 查询命中覆盖索引
SELECT age, name FROM user WHERE age > 20;
聚集索引 vs 非聚集索引
聚集索引 (Clustered Index)
- 数据即索引:索引的叶子节点直接存储完整行数据
- 物理有序:表中的数据行按聚集索引的键值顺序存储
- 唯一性:一张表有且仅有一个聚集索引(InnoDB强制要求)
非聚集索引 (Non-Clustered Index)
- 索引与数据分离:叶子节点存储主键值(InnoDB中)或行指针(MyISAM中)
- 逻辑有序:索引本身有序,但数据行物理存储无序
- 可多个共存:一张表可以创建多个非聚集索引(二级索引)
InnoDB引擎实现
| 特征 | 聚集索引 | 非聚集索引 |
|---|---|---|
| 叶子节点内容 | 存储完整数据行 | 存储主键值 |
| B+树结构 | 主键构建的B+树即数据文件 | 独立B+树结构 |
| 查找流程 | 直接返回数据 | 先查主键,再通过主键查聚集索引(回表) |
关键差异
| 对比维度 | 聚集索引 | 非聚集索引 |
|---|---|---|
| 数据存储方式 | 数据按索引顺序物理存储 | 索引与数据物理分离 |
| 查询速度 | 主键查询极快(直接定位数据) | 需要二次查找(回表) |
| 插入效率 | 顺序插入高效,随机插入可能产生页分裂 | 插入只需更新索引树 |
| 空间占用 | 无额外存储空间 | 需要额外存储索引结构 |
| 更新代价 | 主键修改代价高(需移动数据行) | 只需更新索引树 |
常见误区
误区1:"主键一定是聚集索引"
- 事实:在InnoDB中主键自动成为聚集索引,但若未定义主键:
- 选择第一个UNIQUE且非空的字段
- 否则隐式创建6字节的DB_ROW_ID作为聚集索引
误区2:"非聚集索引查询性能差"
- 优化方案:
- 通过覆盖索引避免回表
- 使用索引条件下推(ICP,Index Condition Pushdown)