Administrator
发布于 2025-10-16 / 31 阅读
0
0

mysql

1.核心架构:不只是“连接池+存储引擎”--->连接层、服务层、存储引擎层和文件系统层:

  • 连接层:

负责处理客户端连接、授权认证、安全等。

每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询都在这个线程中执行。

服务器负责缓存线程,因此不需要为每个新连接创建或销毁线程(线程池)。

  • 服务层:这是MySQL的核心,包括以下组件:

    • 管理服务和工具组件:系统管理和控制工具,例如备份恢复、复制、集群等。

    • SQL接口:接收用户的SQL命令,并返回用户需要查询的结果。支持DML、DDL、存储过程、视图、触发器等。

    • 解析器:对SQL语句进行解析,包括词法分析、语法分析。生成解析树,然后进行预处理(检查表、列是否存在等),最后生成新的解析树。

    • 查询优化器:对解析树进行优化,包括重写查询、决定表的读取顺序、选择合适的索引等。生成执行计划。

    • 缓存和缓冲区:查询缓存(注意:MySQL 8.0已移除查询缓存)。缓冲池、键缓冲区等。

  • 存储引擎层:负责数据的存储和提取。MySQL采用插件式存储引擎架构,支持多种存储引擎,如InnoDB、MyISAM、Memory等。存储引擎是表级别的,不同的表可以使用不同的存储引擎。

    • InnoDB:支持事务、行级锁、外键。使用聚簇索引,数据文件本身就是索引文件。采用MVCC(多版本并发控制)来支持高并发。

    • MyISAM:不支持事务和行级锁(只有表锁)。非聚簇索引,数据文件和索引文件分开。适合读多写少的场景。

    • Memory:数据存储在内存中,速度快,但重启后数据丢失。

    • Archive: 只支持 INSERT 和 SELECT,高压缩比,适用于日志存储。

  • 文件系统层:将数据库的数据和日志存储在文件系统上,包括数据文件、日志文件等。不同的存储引擎有不同的文件格式。

2. 索引:B+Tree 的深度剖析

不要只说“索引就像字典的目录”。

  • 为什么是 B+Tree,而不是 B-Tree 或 Hash?

    • B+Tree 的非叶子节点只存键,不存数据,因此一个页能容纳更多的键,树的高度更低,IO 次数更少。

    • 叶子节点之间有双向指针,支持高效的范围查询(><, BETWEEN)和全表顺序扫描。这是 Hash 索引无法做到的。

  • InnoDB 的聚簇索引:

    • 表数据本身就是索引的一部分,按主键顺序存储。没有主键? InnoDB 会创建一个隐藏的 ROWID 作为聚簇索引。

    • 二级索引(非聚簇索引)的叶子节点存储的是主键值,而不是物理地址。这意味着回表查询:通过二级索引找到主键,再通过主键去聚簇索引中查找完整数据行。这是很多性能问题的根源。

  • 最左前缀原则: 这不仅是 WHERE 条件,还包括 ORDER BY 和 GROUP BY。索引 (a, b, c) 能用于 WHERE a=x AND b=y,也能用于 ORDER BY a, b,但不能用于 WHERE b=y

  • 索引下推: 在 MySQL 5.6 引入。在没有 ICP 时,存储引擎会通过二级索引查询到所有满足 a=x 的记录(即使 b=y 不满足),然后回表,再由 Server 层过滤 b=y。有了 ICP,存储引擎会在二级索引这一层就判断 b=y,只回表那些真正满足所有条件的行,大大减少了回表次数。

  • 覆盖索引: 如果一个索引包含了查询所需要的所有字段,则无需回表。这是终极的优化手段之一。EXPLAIN 的 Extra 列会出现 Using index

3.事务与锁:并发控制的基石

1.ACID靠什么保证?

  • A(Atomicity:原子性)和D(Durability:持久性):靠undolog和redolog

    • redo log:物理日志,记录的是“在某个数据页上做了什么修改”。WAL(Write-AheadLogging)机制保证持久性---事务提交时,先写redolog(顺序写,速度快),再在合适时机刷脏页(随机写,速度慢)。innodb_flush_log_at_trx_commit=1 保证每次提交都刷盘 redo log。

    • undolog:逻辑日志。记录数据修改前的镜像。用于事务回滚(原子性)和 MVCC。

  • I(Isolation:隔离性):靠锁和MVCC保证

  • C(Consistency:一致性):是最终目标由A、I、D共同保证。

2.MVCC(多版本并发控制):

  • 核心是 undo log 链 和 ReadView

  • 每个事务都有一个唯一的事务 ID。

  • 每行数据都有隐藏字段:DB_TRX_ID(最后修改它的事务ID)、DB_ROLL_PTR(指向 undo log 记录的指针)。

  • 当一个事务启动时,它会生成一个 ReadView,其中包含了当前所有活跃事务的 ID 列表。

  • 当这个事务查询数据时,会沿着 undo log 链找到第一个在其 ReadView 创建之前就已经提交的版本。这就实现了非锁定读(快照读)

3.锁机制:

  • 行锁:在索引上实现。如果查询没有走到索引,就会升级为表锁。

  • 间隙锁 和 Next-Key Lock:为了解决幻读问题。Next-Key Lock = 行锁 + 间隙锁。它锁住一个左开右闭的区间。这是在 可重复读 隔离级别下默认的锁算法。

  • 死锁:是正常的现象,关键在于如何快速发现和处理。innodb_lock_wait_timeout 设置超时时间,innodb_deadlock_detect=on 开启死锁检测(默认开启)。

4. 性能调优:从 SQL 到架构

  • 慢查询分析:

    1. 开启慢查询日志 slow_query_log=1

    2. 使用 mysqldumpslow 或 pt-query-digest 工具分析。

    3. 对每一个慢查询,使用 EXPLAIN 查看执行计划。

  • 读 EXPLAIN 输出,关注这些列:

    • type:从好到坏:system > const > eq_ref > ref > range > index > ALL。至少要优化到 range 级别。

    • key:实际使用的索引。

    • rows:预估需要扫描的行数。

    • Extra

      • Using filesort:需要额外的排序,考虑用索引优化。

      • Using temporary:需要创建临时表,常见于 GROUP BY 和 ORDER BY 子句不同。

      • Using index:覆盖索引,好!

  • 系统层面:

    • Buffer Pool:InnoDB 最重要的内存区域。它缓存数据和索引页。通常设置为系统总内存的 50%-80%。监控 Innodb_buffer_pool_reads(物理读)和 Innodb_buffer_pool_read_requests(逻辑读)的比率,如果物理读很高,说明 BP 太小。

    • Log Buffer:redo log 的缓冲区。对于写密集型事务,适当调大 innodb_log_buffer_size


5. 高可用与扩展

  • 主从复制:

    • 原理:主库的 binlog(二进制日志)被从库的 I/O thread 拉取,写入本地的 relay log,再由 SQL thread 应用。

    • 延迟问题:这是经典难题。原因:单线程应用(5.6+ 支持并行复制,但配置复杂)、从库配置较低、网络延迟、大事务。

  • 高可用架构:

    • MHA:传统方案,基于主从复制,在主库宕机时能自动完成故障转移和主从提升。

    • MGR:MySQL 官方提供的基于 Paxos 协议的新型高可用方案。数据强一致性,支持多主写入,是未来的方向。

  • 扩展方案:

    • 读写分离:应用层解耦,写主库,读多个从库。注意主从延迟可能带来的“读不到刚写入数据”的问题。

    • 分库分表

      • 垂直分片:按业务模块分到不同数据库。

      • 水平分片:将一个大表的数据按分片键(如 user_id)分布到多个数据库的相同结构表中。

      • 中间件:ShardingSphere、Vitess 等。

1. 一条SQL查询语句的执行过程

客户端通过连接器连接到MySQL服务器。

查询缓存(如果启用且版本支持),如果缓存命中则直接返回。

解析器进行词法分析和语法分析,生成解析树。

预处理器检查表、列等是否存在,生成新的解析树。

优化器生成执行计划。

执行器调用存储引擎的接口执行查询。

存储引擎读取数据并返回给执行器,然后返回给客户端。

3. 锁机制

InnoDB支持行级锁和表级锁,默认使用行级锁。

行级锁分为共享锁(S锁)和排他锁(X锁)。

意向锁:表级锁,用于快速判断表内是否有行级锁。

4. MVCC(多版本并发控制)

通过undo日志和读视图(Read View)来实现。

每个事务在开始时都会创建一个读视图,从而在事务执行期间看到一致的数据快照。

5. 索引原理(B+树)

InnoDB使用B+树作为索引结构。

聚簇索引:叶子节点存储整行数据。

非聚簇索引(二级索引):叶子节点存储主键值,需要回表查询。

6. 缓冲池(Buffer Pool)

在内存中缓存数据和索引,减少磁盘IO。

采用LRU算法进行页面淘汰。

7. 日志刷盘机制

重做日志缓冲:事务提交时,redo log刷盘(可以通过配置控制刷盘策略)。

二进制日志(binlog):用于主从复制和数据恢复,在事务提交时写入。

17.MySQL的MVCC机制?

MVCC(多版本并发控制)是一种提高数据库并发性能的方法。InnoDB通过为每行记录添加版本号(系统版本号)来实现。在事务开始时,会记录当前系统的版本号,事务中读取数据时,只读取版本号早于当前事务版本的数据,从而实现非阻塞读。

10.MySQL中CHAR和VARCHAR的区别?

CHAR是固定长度的字符串,如果存入的数据长度小于指定长度,会用空格填充,检索时会去掉尾部空格。

VARCHAR是可变长度的字符串,存储的是实际字符串加上一个记录字符串长度的字节(超过255时需要两个字节)。

在存储空间上,CHAR总是使用固定的空间,而VARCHAR则根据实际数据长度使用空间。

11.什么是索引?MySQL中常见的索引类型有哪些?

索引是帮助MySQL高效获取数据的数据结构,类似于书的目录。

常见索引类型:

主键索引(PRIMARY KEY):唯一且非空。

唯一索引(UNIQUE):唯一但允许空值。

普通索引(INDEX):基本的索引,无唯一性限制。

复合索引:多个列组合的索引。

全文索引(FULLTEXT):用于全文搜索。

12.请解释MySQL的存储引擎InnoDB和MyISAM的区别?

InnoDB支持事务,MyISAM不支持。

InnoDB支持外键,MyISAM不支持。

InnoDB是行级锁,MyISAM是表级锁。

InnoDB支持崩溃后的安全恢复,MyISAM不支持。

InnoDB使用聚簇索引(索引和数据放在一起),MyISAM使用非聚簇索引(索引和数据分开)。

13.什么是脏读、不可重复读和幻读?

脏读:一个事务读取了另一个事务未提交的数据。

不可重复读:一个事务内多次读取同一数据,由于其他事务的修改导致数据不一致。

幻读:一个事务内多次查询同一范围的数据,由于其他事务的插入操作导致返回的记录数不同。

14.MySQL的隔离级别有哪些?

读未提交(Read Uncommitted):最低级别,允许脏读。

读已提交(Read Committed):只能读取已提交的数据,避免脏读,但不可重复读和幻读仍可能发生。

可重复读(Repeatable Read):确保同一事务中多次读取同一数据的结果是一致的,避免脏读和不可重复读,但幻读仍可能发生(InnoDB通过MVCC避免了幻读)。

串行化(Serializable):最高级别,完全隔离,避免脏读、不可重复读和幻读,但性能最低。

15.如何优化MySQL查询性能?

使用索引:确保查询使用了适当的索引。

避免SELECT *:只选择需要的列。

使用连接(JOIN)代替子查询。

避免在WHERE子句中对字段进行函数操作。

使用EXPLAIN分析查询执行计划。

优化表结构,如规范化或反规范化。

调整服务器配置,如缓冲池大小。

16.什么是覆盖索引?

覆盖索引是指一个索引包含了查询所需要的所有字段,不需要回表查询数据行。

18.如何定位和解决慢查询?

使用慢查询日志,记录执行时间超过指定阈值的SQL语句。

使用EXPLAIN分析慢查询的SQL,查看执行计划。

检查是否使用了索引,如果没有,考虑添加索引。

优化SQL语句,避免全表扫描,避免使用!=或<>操作符,避免OR连接条件等。

19.MySQL中如何实现分页?有什么需要注意?

使用LIMIT子句,例如:SELECT * FROM table LIMIT 10 OFFSET 20;(从第20条开始取10条)

注意:在大数据量下,偏移量越大,分页查询效率越低。可以通过使用条件(如WHERE id > 上一页最大ID)来优化。

20.什么是死锁?如何避免死锁?

死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种互相等待的现象。

避免死锁的方法:

尽量让多个事务按相同的顺序访问资源。

降低事务的隔离级别,如使用读已提交。

保持事务简短,减少锁的持有时间。

使用死锁检测和超时机制。

21.MySQL中如何备份和恢复数据?

备份:可以使用mysqldump工具,例如:mysqldump -u username -p database_name > backup.sql

恢复:使用mysql命令,例如:mysql -u username -p database_name < backup.sql

22.主从复制?

原理:主库binlo(二进制日志)被从库I/O thread 拉取,写入本relay log(中继日志)SQL thread 重放中继日志中的事件。

延迟问题:这是经典难题。原因:单线程应用(5.6+支持并行复制,但是配置复杂)、从库配置低、网络延迟、大事务。

23.如何监控MySQL的性能?

使用SHOW STATUS命令查看系统状态变量。

使用SHOW PROCESSLIST查看当前连接和线程状态。

使用性能模式(Performance Schema)和信息模式(INFORMATION_SCHEMA)来获取更详细的性能数据。

使用第三方监控工具,如Percona Monitoring and Management (PPM)、Prometheus等。


评论