MySQL 学习记录
MySQL 日志文件
MySQL 日志文件有很多,包括:
- 错误日志(error log):记录启动、运行、关闭过程,帮助定位问题
- 慢查询日志(slow query log):记录执行时间超过
long_query_time的 SQL,用于性能优化 - 一般查询日志(general log):记录所有请求,无论是否执行成功
- 二进制日志(bin log):记录 DDL 和 DML(不含 SELECT/SHOW),以事件形式保存在二进制文件中,用于主从复制和数据恢复
InnoDB 存储引擎特有的日志:
- 重做日志(redo log):记录事务对数据页的物理修改,保证崩溃恢复(WAL 机制)
- 回滚日志(undo log):记录事务修改前的旧值,用于回滚和 MVCC 读
binlog 和 redo log 有什么区别?
| 维度 | binlog | redo log |
|---|---|---|
| 层级 | Server 层,所有存储引擎 | InnoDB 引擎特有 |
| 内容 | 逻辑日志(SQL 或行变更) | 物理日志(数据页修改) |
| 写入时机 | 事务提交时一次写入 | 事务进行中持续写入 |
| 写入方式 | 追加,不覆盖 | 循环写,空间固定 |
二者配合实现崩溃安全 + 主从复制:redo log 保证本地崩溃恢复,binlog 保证跨节点数据同步。
count 统计对比
执行效果
count(*):统计所有行,不忽略 NULLcount(1):统计所有行,不忽略 NULL,与count(*)语义等价count(列名):只统计该列非 NULL 的行
执行速度
- 列名为主键时,
count(列名)与count(1)差距不大 - 列名非主键且无索引时,
count(1)/count(*)通常更快 - 有主键时,
count(主键)最优 - 单列表时,
count(*)最优
InnoDB 不维护精确行数元数据,count(*) 在大表上需要扫描索引或全表,应尽量走最小的二级索引。
索引
聚簇索引 vs 二级索引
InnoDB 表数据按主键顺序存储在聚簇索引(叶子节点存完整行)。二级索引叶子节点存主键值,查询需回表。
最左前缀原则
联合索引 (a, b, c) 可用于 a、a,b、a,b,c 的查询条件,不能跳过左侧列。
覆盖索引
查询列全部在索引中即可避免回表,如 SELECT id, name FROM user WHERE name = ? 走 (name, id) 索引。
事务与隔离级别
| 级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 不会 | 可能 | 可能 |
| REPEATABLE READ(默认) | 不会 | 不会 | 可能* |
| SERIALIZABLE | 不会 | 不会 | 不会 |
*InnoDB 在 RR 级别通过 MVCC + 间隙锁(Gap Lock)在很大程度上避免幻读。
MVCC 简述
多版本并发控制:每行有隐藏列 trx_id 和回滚指针,Read View 判断版本可见性,实现非锁定读。undo log 构成版本链,支持一致性读和回滚。