菜单

MySQL

相关源文件

目的与范围

本文档全面概述了MySQL数据库系统,重点关注其架构、存储引擎、索引机制、事务管理和查询优化。这里涵盖的内容旨在帮助开发人员和数据库管理员理解MySQL的内部工作原理,以便更好地利用和优化MySQL数据库操作。

有关更广泛的数据库概念以及与其他数据库系统的比较,请参阅数据库

MySQL简介

MySQL是一个开源的关系型数据库管理系统(RDBMS),它使用结构化查询语言(SQL)进行数据库操作。它广泛用于存储和管理各种应用程序中的数据,从小型网站到大型企业系统。

MySQL的主要特点包括:

  • 开源,采用双重许可(GPL/商业)
  • 跨平台支持
  • ACID事务处理能力(使用InnoDB)
  • 支持多种存储引擎
  • 全面的索引选项
  • 强大的安全特性
  • 默认端口号为3306

MySQL之所以被广泛选择,主要是因为它具有可靠性、高性能、易用性以及强大的社区支持。

来源:docs/database/mysql/mysql-questions-01.md:52-70

MySQL 架构

MySQL采用客户端-服务器架构,多个客户端连接到MySQL服务器。服务器负责核心功能,包括查询解析、优化、缓存和数据存储。

基本架构组件

MySQL服务器由几个关键组件组成:

  1. 连接池:管理客户端连接和身份验证
  2. 查询解析器和分析器:解析SQL查询并进行语法分析
  3. 查询优化器:确定最高效的执行计划
  4. 执行引擎:根据计划执行查询
  5. 存储引擎:管理数据存储和检索
  6. 数据文件和日志:存储数据和事务日志的物理文件

来源:docs/database/mysql/mysql-questions-01.md:192-206, docs/database/mysql/how-sql-executed-in-mysql.md

SQL执行过程

当SQL查询发送到MySQL时,它会经过以下步骤:

  1. 连接阶段:客户端通过适当的身份验证建立连接
  2. 查询缓存检查:MySQL检查缓存中是否存在相同的查询结果(注意:MySQL 8.0已移除)
  3. 解析:查询被解析成一个解析树
  4. 预处理:检查查询结构是否正确
  5. 查询优化:优化器选择最佳执行计划
  6. 执行:存储引擎根据计划执行查询并返回结果
  7. 返回结果:将结果发送回客户端

来源:docs/database/mysql/how-sql-executed-in-mysql.md, docs/database/mysql/mysql-questions-01.md:367-401

存储引擎

MySQL的架构允许使用可插拔的存储引擎,这些组件负责处理不同表类型的SQL操作。

常见存储引擎

引擎事务支持锁定级别特性最佳用途
InnoDB行级ACID兼容,外键,崩溃恢复大多数应用,事务性工作负载
MyISAM表级对读密集型工作负载更快,全文索引读密集型应用,旧系统
内存表级内存表,速度极快临时表,快速查找
Archive行级高压缩存储历史数据,日志
CSV表级CSV文件格式与其他应用程序进行数据交换

自MySQL 5.5.5起,InnoDB是默认的存储引擎。

来源:docs/database/mysql/mysql-questions-01.md:207-248, docs/database/mysql/mysql-questions-01.md:268-346

InnoDB与MyISAM对比

由于支持事务、行级锁定和崩溃恢复功能,InnoDB是大多数用例的推荐存储引擎。

来源:docs/database/mysql/mysql-questions-01.md:268-346

MySQL索引

索引是数据结构,通过减少所需磁盘I/O操作的数量来提高数据检索操作的速度。

索引数据结构

MySQL主要使用B+树作为索引的底层数据结构,尤其是在InnoDB中。B+树非常适合数据库索引,因为:

  1. 它维护排序数据,以便高效进行范围查询
  2. 它具有平衡结构,确保性能一致
  3. 它通过高分支因子最大限度地减少磁盘I/O
  4. 所有叶子节点都在同一层,提供可预测的搜索时间

来源:docs/database/mysql/mysql-index.md:14-37, docs/database/mysql/mysql-index.md:38-128

MySQL中的索引类型

MySQL支持多种索引类型:

  1. 主键:每条记录的唯一标识符,不能包含NULL值
  2. 唯一索引:确保索引列(或列)中的所有值都是唯一的,允许NULL值
  3. 普通索引:标准索引,没有唯一性约束
  4. 复合索引:对多个列的索引
  5. 空间索引:用于几何数据类型
  6. 全文索引:用于文本搜索

按数据结构分类:

  • B-Tree/B+ Tree索引:大多数引擎的默认值
  • 哈希索引:在Memory引擎中找到
  • R-Tree索引:用于空间数据
  • 倒排索引:用于全文搜索

按应用目的分类:

  • 聚集索引:决定表数据的物理顺序(InnoDB中的主键)
  • 二级索引:提供高效访问路径的附加索引

来源:docs/database/mysql/mysql-index.md:136-165, docs/database/mysql/mysql-questions-01.md:80-106

聚集索引与非聚集索引

在InnoDB中:

  • 主键始终是聚集索引
  • 二级索引包含主键值,而不是直接的行指针
  • 通过二级索引访问数据需要额外的聚集索引查找

来源:docs/database/mysql/mysql-index.md:166-185, docs/database/mysql/mysql-questions-01.md:318-326

索引最佳实践

  1. 为WHERE、JOIN、ORDER BY和GROUP BY中使用的列创建索引
  2. 为索引列使用尽可能小的数据类型
  3. 创建复合索引时,将选择性最高的列放在前面
  4. 避免为基数低的列创建索引
  5. 考虑为大型字符串列使用前缀索引
  6. 不要过度索引表——每个索引都会增加写操作的开销
  7. 使用EXPLAIN分析查询以验证索引使用情况

来源:docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md, docs/database/mysql/mysql-index.md

事务管理

事务是作为单个逻辑工作单元执行的一系列操作。MySQL的InnoDB存储引擎提供了完整的ACID事务支持。

MySQL中的ACID属性

事务隔离级别

InnoDB支持所有四种标准的SQL事务隔离级别。

隔离级别脏读不可重复读幻读锁定实现
READ UNCOMMITTED可能可能可能最小化锁定
READ COMMITTED避免可能可能行级锁定,为每个语句创建读视图
REPEATABLE READ避免避免可能*行级锁定,为事务创建读视图
SERIALIZABLE避免避免避免完全锁定(读操作使用共享锁)

*InnoDB的REPEATABLE READ通过多版本并发控制(MVCC)和间隙锁(gap locking)实际上避免了大多数幻读。

MySQL的默认隔离级别是REPEATABLE READ

来源:docs/database/mysql/mysql-questions-01.md:463-592, docs/database/mysql/transaction-isolation-level.md

事务实现机制

InnoDB通过几个关键机制实现事务:

  1. 锁定:通过各种锁类型提供并发控制

    • 共享锁(S锁)用于读取
    • 排他锁(X锁)用于写入
    • 意向锁(IS/IX锁)用于指示表级别的锁定意图
    • 行级锁(记录锁)
    • 间隙锁(Gap locks)用于防止幻读
    • next-key锁(记录锁+间隙锁)
  2. MVCC(多版本并发控制):允许事务在某个时间点看到数据库的快照,通过以下方式实现:

    • 事务ID
    • Undo日志用于维护数据的旧版本
    • 读视图(Read views)用于确定记录可见的版本
  3. 日志:

    • Redo日志用于崩溃恢复(持久性)
    • Undo日志用于回滚和MVCC(原子性和隔离性)
    • Binlog日志用于复制和时间点恢复

来源:docs/database/mysql/mysql-questions-01.md:593-675, docs/database/mysql/mysql-logs.md

MySQL日志

MySQL使用各种日志文件来支持恢复、复制和故障排除等操作。

关键日志类型

Binlog(二进制日志)

二进制日志包含数据库数据和结构的所有更改记录。它用于:

  1. 复制:将更改发送到副本服务器
  2. 时间点恢复:将数据库恢复到特定时间点
  3. 审计:跟踪数据库的所有修改

Binlog格式:

  • 基于语句(Statement-based):记录SQL语句
  • 基于行(Row-based):记录行级更改
  • 混合(Mixed):根据语句类型自动在两者之间切换

Redo日志(重做日志)

Redo日志是InnoDB特有的日志,提供崩溃恢复功能并实现ACID的持久性。其工作原理如下:

  1. 当事务修改数据时,更改首先写入内存中的缓冲池
  2. 同时,更改记录被写入redo日志缓冲区
  3. redo日志缓冲区在提交时或定期刷新到磁盘上的redo日志文件
  4. 在崩溃后,InnoDB使用redo日志重放尚未写入数据文件的未提交更改

Redo日志以循环方式写入固定大小的文件,并使用检查点机制来跟踪哪些更改已应用到数据文件。

Undo日志(回滚日志)

Undo日志存储了回滚事务所需的信息,并用于:

  1. 事务回滚:如果事务被中止,则撤销更改
  2. 多版本并发控制(MVCC):通过构建记录的先前版本来提供一致的读取视图

Undo日志存储在undo表空间中,并作为InnoDB系统表空间的一部分进行管理。

来源:docs/database/mysql/mysql-logs.md, docs/database/mysql/mysql-questions-01.md:401-415

MySQL性能优化

优化MySQL性能涉及多个方面,从数据库设计到查询优化和服务器配置。

查询优化技巧

  1. 使用EXPLAIN命令分析查询执行计划
  2. 根据查询模式创建适当的索引
  3. 通过正确索引连接列来优化JOIN操作
  4. 使用LIMIT子句限制大型查询的结果集
  5. **避免使用SELECT ***;仅指定需要的列
  6. 使用覆盖索引,使查询无需访问数据行即可满足
  7. 避免在WHERE子句中使用索引列的函数
  8. 对于值有限的列,考虑使用ENUM而不是VARCHAR
  9. 对重复查询使用预编译语句
  10. 在适当的情况下进行反规范化以支持读密集型工作负载

模式和索引优化

  1. 选择合适的数据类型:

    • 使用能够可靠存储数据的最小数据类型
    • 使用INT存储IP地址而不是VARCHAR(使用INET_ATON和INET_NTOA函数)
    • 在适用的情况下使用UNSIGNED来加倍正数范围
  2. 索引最佳实践:

    • 为WHERE、JOIN、ORDER BY和GROUP BY子句中使用的列创建索引
    • 创建复合索引时,将选择性最高的列放在前面
    • 创建索引时考虑索引基数
    • 为经常运行的查询使用覆盖索引
    • 避免过度索引以减少写开销
  3. 表设计:

    • 除非有特定原因,否则所有表都使用InnoDB
    • 设置合适的字符集和排序规则(推荐UTF8MB4)
    • 为表和列添加注释
    • 控制表大小(考虑分区或归档旧数据)
    • 避免在经常查询的列中使用TEXT/BLOB

来源:docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md

服务器配置优化

优化时需要考虑的关键配置变量

参数描述优化考虑
innodb_buffer_pool_size分配给InnoDB缓冲池的内存对于专用数据库服务器,设置为可用RAM的50%-80%
innodb_log_file_sizeredo日志文件的大小较大的文件大小可以提高性能,但会增加恢复时间
max_connections允许的最大连接数根据预期的并发连接数设置
query_cache_size查询缓存的大小(MySQL < 8.0)通常在MySQL 5.7+中禁用,在MySQL 8.0中移除
tmp_table_size内存中临时表的最大大小对于具有大型临时表的查询,请增加此值
sort_buffer_size用于排序的缓冲区对于复杂的ORDER BY操作,请增加此值
join_buffer_size用于无索引的JOIN操作的缓冲区对于不使用索引的JOIN操作,请增加此值
innodb_flush_log_at_trx_commit控制redo日志的刷新行为1表示ACID兼容,2或0表示性能
innodb_flush_method用于刷新数据的 메서드在Linux上,O_DIRECT通常可以提高性能

来源:docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md

结论

MySQL是一个强大且通用的关系型数据库系统,拥有丰富的功能集,可以针对各种工作负载进行优化。理解其架构、存储引擎(特别是InnoDB)、索引机制、事务管理和日志系统对于有效的数据库管理和应用程序开发至关重要。

通过妥善利用MySQL的功能,特别是其索引和事务特性,并应用本文档中概述的优化技术,您可以构建高性能、可靠的数据库系统,满足应用程序的需求。