MySQL知识整理二

一、日志系统

1. redo log(重做日志)

  • 属于InnoDB 引擎层****。

  • 作用:保证事务持久性,崩溃恢复

  • 机制:**Write Ahead Log(WAL)**预写日志,先写redo log再异步写磁盘,提升性能

  • 结构:固定大小,循环写,不会无限膨胀

  • 总结:宕机重启靠 redo log 恢复数据,保证提交了就不丢**。**

2. undo log(回滚日志)

  • 属于InnoDB 引擎层

  • 作用:保证事务 原子性 ,回滚使用;实现 MVCC 多版本并发控制

  • 总结:回滚靠 undo log,MVCC 也靠 undo log

3. binlog(归档日志)

  • 属于server层,与引擎无关,追加写,文件会不断生成

  • 作用:主从同步;数据基于时间点恢复

  • 与 redo log 区别:redo 是 InnoDB 独有,binlog 是 Server 层,逻辑日志

4. 两阶段提交 2PC

保证 redo log 和 binlog 数据一致,是主从同步 + 数据恢复的基础

  • ① 写 redo log,状态 prepare
  • ② 写 binlog
  • ③ 提交 redo log,状态 commit

二、高可用架构

核心目标:故障自动切换;数据不丢或少丢;业务不间断;读写分离、水平扩展

1、主从复制(高可用基石)

(1) 复制原理

  • ① 主库写入,生成 binlog

  • ② 从库通过 IO 线程拉取 binlog,写入 relay log

  • ③ 从库 SQL 线程重放 relay log,保持数据一致

(2) 3种复制模式

  • 异步复制:主库不关心从库是否同步完,性能最好,但可能丢数据

  • 半同步复制:至少一个从库 ACK 后才提交,数据更安全,性能略有下降

  • 组复制(MGR):分布式一致性协议,强一致,高可用

(3) 主从延迟问题

  • 原因:大事务、从库压力大、网络延迟

  • 解决:

    • 并行复制

    • 减少大事务:大事务拆分为小事务、禁止在事务里调用外部接口、批量操作分批提交

    • 优化SQL,减少从库压力

    • 降低主库写入压力:读写分离、热点数据分离、异步化、削峰填谷

2、主流高可用方案

2.1. MHA(Master High Availability)

最经典、最常用

  • 架构:1 主 + N 从 + MGR 管理节点
  • 优点:成熟稳定、切换快、对侵入小
  • 缺点:
    • 需手动 / 脚本部署
    • 无法自动补主,切完后需要手动加从
    • 依赖 VIP 漂移

2.2. MGR(MySQL Group Replication)

官方推荐、未来趋势、强一致

  • 单主模式 / 多主模式
  • 基于 Paxos 分布式一致性协议
  • 自动故障检测、自动选主、自动恢复
  • 优点:强一致、高可用、无需额外组件
  • 缺点:对网络要求高、性能一般、表必须有主键

2.3. InnoDB Cluster + MySQL Router

  • 基于 MGR 封装
  • 管理更简单
  • Router 做读写分离、负载均衡、故障透明

2.4. 主从 + Keepalived(VIP)

  • 简单粗暴
  • 主库挂了,VIP 飘到从库
  • 优点:简单
  • 缺点:切换不智能、可能脑裂、数据一致性无保障

3、读写分离

  • 写:主库
  • 读:从库
  • 实现方式:
    • 应用内部分离
    • Sharding-JDBC
    • MySQL Router
    • MyCat

三、分库分表

分库分表作用:水平扩容,把压力分散到多个库、多张表,提高并发和容量。解决单表数据过大(千万~亿级)导致的:

  • 查询慢、索引大、IO 高
  • 写入性能瓶颈
  • 备份、DDL 极其困难

1、拆分方案

  • 垂直拆分

    • 按业务拆分,如用户库、订单库、商品库

    • 优点:简单清晰,隔离业务

    • 缺点:不能解决单表过大问题

  • 水平拆分

    • 同一张表的数据按规则切到多张表 / 多个库,例如:order 拆成 order_0 ~ order_15

    • 优点:真正解决单表容量、并发瓶颈

    • 缺点:复杂度高,需要中间件支持

2、常见分片策略

  • 范围分片

    • 按 ID 范围、时间范围,如:1~1000w 放表 1,1000w~2000w 放表 2
    • 优点:扩容方便
    • 缺点:容易出现数据倾斜、热点库
  • 哈希分片(最常用)

    • shard_idx = hash(user_id) % 分片数

    • 优点:数据分布均匀

    • 缺点:扩分片需要rehash 迁移数据

  • 一致性哈希

    • 解决扩缩容大量迁移问题
    • 一般中间件内置,业务不用自己写
  • 按业务字段分片

    • 订单按 user_id,日志按日期

    • 保证同用户数据在同分片,方便查询

3、分库分表带来的问题

  • 跨分片分页、排序、count 复杂
  • 跨库事务难保证(分布式事务)
  • join 困难,不能随意 join 不同分片表
  • 分布式 ID,不能用本地自增主键
  • 扩容、数据迁移成本高
  • 运维复杂度提升,排错难

4、分布式 ID 方案

分表后不能用 MySQL auto_increment,常用:

  • 雪花算法(Snowflake)
  • 号段模式(Segment)
  • Redis 自增
  • UUID(不推荐,无序导致索引性能差)

5、分布式事务

  • 最大努力交付
  • TCC
  • SAGA
  • 本地消息表
  • 2PC/3PC(性能差,少用)

实际业务尽量避免分布式事务

  • 按同字段分片,让相关数据在同库
  • 使用最终一致性

6、分库分表常用中间件

  • 客户端模式(Java 生态主流):**Sharding-JDBC(ShardingSphere)**轻量、无部署、性能高

  • 服务端代理模式:MyCat、Sharding-Proxy、DBLE

四、SQL优化

1. 定位慢SQL

  • ① 开启 慢查询日志
  • ② 使用 show processlist 看耗时 SQL
  • ③ 使用 profiling 查看执行耗时
  • ④ 生产用监控:Prometheus、Grafana、SkyWalking

2. 优化步骤

  • ① 用 explain 查看执行计划
  • ② 看是否走索引、是否回表、是否文件排序
  • ③ 优化索引、优化 SQL、分库分表

3. 查看执行计划

重点字段

  • type:优到最差 system > const > eq_ref > ref > range > index > ALL,最好到 range 以上,refeq_refconst 最优
  • key:实际使用的索引
  • rows:扫描行数越少越好
  • Extra
    • Using index:覆盖索引,极好
    • Using where:正常
    • Using filesort:文件排序,需优化
    • Using temporary:用到临时表,需优化

4. 索引优化

  • where、order by、group by、join 字段建索引
  • 优先建 联合索引 ,遵循最左匹配
  • 联合索引,等值放前,范围放后
  • 使用 覆盖索引,避免回表
  • 禁止在低基数列建索引(性别、状态)
  • 禁止无序主键(UUID),避免页分裂
  • 单表索引控制在 3~5 个

5. SQL语句优化

  • 禁止 select *: 只查需要的字段,更容易命中覆盖索引。

  • 避免索引失效:

    • 不在索引列做运算、函数、类型转换
    • 禁止 like '%xxx' 前置模糊
    • 避免 or 一侧无索引
    • 避免 !=is nullnot in 导致索引失效
  • 优化分页:大分页 limit 100000,20 极慢,用主键过滤where id>100000 limit 10

  • 优化 in:值太多用 in 会导致索引失效或全表扫描拆分批、或改用 join

  • 避免 order by 导致 filesort:排序字段建索引,或使用覆盖索引

  • 避免 group by 产生临时表:分组字段建索引

  • JOIN优化:

    • 小表驱动大表

    • 关联字段必须建索引

    • 尽量不超过3张表JOIN

    • 禁止JOIN大结果集

  • 子查询优化:

    • 尽量将 in (子查询) 改为 join;

    • 避免相关子查询(循环执行)

  • 大表优化:

    • 读写分离;

    • 分库分表(sharding);

    • 冷热数据分离;

      加缓存(Redis);

    • 避免大事务、批量操作分批执行

6. 总结

SQL 优化主要从索引、SQL 语句、业务设计、数据库架构四个层面入手:

  • 通过 explain 分析执行计划,确保命中索引;
  • 建立合理的联合索引、覆盖索引,避免索引失效;
  • 优化 SQL 写法,禁止 select *,避免函数运算、前置模糊、无效 in
  • 优化分页、排序、分组,减少 filesort 和临时表;
  • 大表采用分库分表、读写分离、缓存等架构优化;
  • 控制事务大小,避免锁等待与主从延迟。

五、常见问题

  • MySQL 为什么用 B + 树?

B+ 树矮胖 ,IO 次数少;叶子节点双向链表,范围查询 / 排序极快

  • varchar (50) 和 varchar (200) 区别?

存储空间一样,但内存临时表大小不同,尽量用合适长度

  • 大表怎么加索引不锁表?

大表不能直接执行普通 alter,会锁表导致业务不可用

正确方案:

① MySQL 5.6 及以上使用在线 DDL ,指定 ALGORITHM=INPLACE, LOCK=NONE 实现无锁加索引;

② 超大表使用第三方工具 pt-osc 或 gh-ost,通过临时表 + 增量同步方式平滑变更;

③ 操作选择低峰期进行,并关注主从延迟与数据库负载

  • 哪些情况会导致索引失效?

索引列运算、函数、隐式转换

② like '%xx' 前置模糊

③ or 一侧无索引

④ != / not in / is null 优化器放弃索引

  • 事务 ACID 分别靠什么保证?

原子性:undo log

一致性:约束 + 事务整体

隔离性:MVCC + 锁

持久性:redo log

  • RC 和 RR 的本质区别是什么?

Read View 生成时机不同:RC每次查询生成新的,RR事务开始时生成一次

  • MySQL 性能瓶颈怎么排查?

慢查询 → explain → 索引优化 → 分库分表 → 硬件升级

  • 主键用自增 id 还是 uuid?

自增 id:连续、索引性能高;uuid:无序、页分裂、性能差

相关推荐
Polar__Star3 小时前
如何在 AWS Lambda 中正确使用临时凭证生成 S3 预签名 URL
jvm·数据库·python
Lucifer三思而后行3 小时前
zCloud 中 Oracle 实例状态未知问题记录
数据库·oracle
island13143 小时前
最详细VMware Workstation 17 上安装 Ubuntu 系统
linux·数据库·ubuntu
卢傢蕊3 小时前
MongoDB
数据库·mongodb
m0_743623923 小时前
React 自定义 Hook 的命名规范与调用规则详解
jvm·数据库·python
古城小栈3 小时前
GORM 操作 PostgreSQL 高级类型
数据库·postgresql
ward RINL3 小时前
redis分页查询
数据库·redis·缓存
Treh UNFO3 小时前
Redis-配置文件
数据库·redis·oracle
iNgs IMAC4 小时前
Redis之Redis事务
java·数据库·redis