Mysql相关知识:存储引擎、sql执行流程、索引失效

文章目录

MySQL 存储引擎

一、MySQL 存储引擎概述

存储引擎是 MySQL 的核心组件,负责数据的存储、读取和管理。不同的引擎在事务支持、锁机制、性能等方面有显著差异。MySQL 支持多种存储引擎,可通过以下命令查看所有支持的引擎:

sql 复制代码
SHOW ENGINES;

二、常见存储引擎对比

引擎 特点 适用场景 默认启用
InnoDB ✅ 支持事务(ACID) ✅ 行级锁 ✅ 外键约束 ✅ 崩溃恢复能力 ✅ 聚簇索引(数据与索引绑定) 高并发读写、需要事务的场景(如电商、金融) ✅ 5.5+ 默认
MyISAM ❌ 不支持事务 ❌ 表级锁 ✅ 全文索引 ✅ 较高的读取速度 ❗ 数据损坏后恢复困难 只读或读多写少(如日志分析、静态数据) ❌ 需手动启用
Memory ✅ 数据存储在内存中 ✅ 极快读写速度 ❌ 服务重启后数据丢失 ❌ 表级锁 临时表、缓存、快速计算中间结果 ❌ 需手动启用
Archive ✅ 高压缩比存储 ✅ 仅支持 INSERT/SELECT ❌ 不支持索引和更新 归档历史数据(如日志归档) ❌ 需手动启用
CSV ✅ 数据以 CSV 格式存储 ❌ 不支持索引、事务、分区 与外部系统交换 CSV 数据 ❌ 需手动启用

三、核心引擎详解

1. InnoDB
  • 核心优势
    • 事务支持 :通过 BEGIN, COMMIT, ROLLBACK 保证数据一致性。
    • 行级锁:仅锁定操作的行,提高并发性能。
    • 外键约束:确保关联表的数据完整性。
    • MVCC(多版本并发控制):读写操作互不阻塞。
  • 存储结构
    • 数据与索引存储在 .ibd 文件中(使用独立表空间时)。
    • 采用 B+树聚簇索引,主键索引的叶节点直接包含行数据。
2. MyISAM
  • 核心特点
    • 非聚簇索引 :索引和数据文件分离(.MYI 索引文件 + .MYD 数据文件)。
    • 表级锁:写操作会锁定整个表,并发性能低。
    • 压缩表 :通过 myisampack 工具压缩,节省存储空间。
  • 典型问题
    • 崩溃后可能需手动修复(REPAIR TABLE 命令)。
    • 不支持事务,数据一致性依赖应用层逻辑。

四、如何选择存储引擎?

场景 推荐引擎 理由
需要事务或高并发写操作 InnoDB 事务和行级锁保证数据一致性和并发性能
只读查询为主,无事务需求 MyISAM 读取速度快,占用资源少(但需权衡数据安全风险)
临时数据处理或缓存 Memory 内存存储实现毫秒级响应,但需注意数据丢失风险
历史数据归档(如日志) Archive 高压缩比节省存储空间,适合低频访问数据

五、引擎操作命令

1. 查看表的存储引擎
sql 复制代码
SHOW TABLE STATUS LIKE '表名';
2. 修改表的存储引擎
sql 复制代码
-- 修改单个表
ALTER TABLE 表名 ENGINE=InnoDB;

-- 修改全局默认引擎(需配置 my.cnf/my.ini)
[mysqld]
default-storage-engine=InnoDB
3. 引擎与性能优化
  • InnoDB :调整 innodb_buffer_pool_size(建议设为物理内存的 70%~80%)。
  • MyISAM :优化 key_buffer_size 以提高索引缓存效率。

六、示例对比

场景:频繁更新的订单表 vs 只读的产品分类表
  • 订单表 :使用 InnoDB,保障订单状态更新、支付事务的原子性。
  • 分类表 :使用 MyISAM(若无需事务),加速分类信息的读取。

七、总结

引擎 事务 锁粒度 索引类型 数据安全 适用场景
InnoDB 支持 行级锁 聚簇索引 高(崩溃恢复) 通用型、高并发写
MyISAM 不支持 表级锁 非聚簇索引 + 全文索引 读多写少、静态数据
Memory 不支持 表级锁 哈希索引 无(内存存储) 临时数据、缓存

根据业务需求选择合适的引擎是数据库设计的关键步骤!如果需要进一步探讨特定场景的引擎优化,可以继续交流。

索引失效

MySQL 中,索引失效会导致查询无法利用索引来加速,从而进行全表扫描,降低查询性能。以下是常见的索引失效情况:

1. 索引列使用函数或表达式

当对索引列使用函数或表达式时,MySQL 无法直接使用索引来定位数据,从而导致索引失效。

sql 复制代码
-- 假设 age 列有索引,以下查询索引会失效
SELECT * FROM users WHERE YEAR(birth_date) = 1990;

可以将查询改写为范围查询,避免对索引列使用函数:

sql 复制代码
SELECT * FROM users WHERE birth_date BETWEEN '1990-01-01' AND '1990-12-31';

2. 隐式类型转换

如果查询条件中的数据类型与索引列的数据类型不一致,MySQL 会进行隐式类型转换,这可能会导致索引失效。

sql 复制代码
-- 假设 id 列是整数类型,以下查询索引会失效
SELECT * FROM users WHERE id = '123';

应确保查询条件的数据类型与索引列的数据类型一致:

sql 复制代码
SELECT * FROM users WHERE id = 123;

3. 范围查询右侧的索引列失效

对于组合索引,MySQL 遵循最左前缀原则。如果在查询条件中使用了范围查询(如 ><BETWEEN 等),范围查询右侧的索引列将无法使用索引。

sql 复制代码
-- 假设存在组合索引 (col1, col2, col3)
SELECT * FROM table_name WHERE col1 = 'value1' AND col2 > 10 AND col3 = 'value3';
-- 这里 col3 无法使用索引

4. 模糊查询以通配符开头

在使用 LIKE 进行模糊查询时,如果通配符 % 出现在字符串的开头,MySQL 无法使用索引来定位数据。

sql 复制代码
-- 以下查询索引会失效
SELECT * FROM users WHERE name LIKE '%John';

如果业务允许,可以将查询改写为不以通配符开头的形式:

sql 复制代码
SELECT * FROM users WHERE name LIKE 'John%';

5. OR 条件导致索引失效

当查询条件中使用 OR 连接多个条件时,如果 OR 两边的条件没有都使用索引,可能会导致索引失效。

sql 复制代码
-- 假设 col1 和 col2 都有索引,但以下查询可能会全表扫描
SELECT * FROM table_name WHERE col1 = 'value1' OR col2 = 'value2';

可以将查询拆分为两个查询,然后使用 UNION 连接:

sql 复制代码
SELECT * FROM table_name WHERE col1 = 'value1'
UNION
SELECT * FROM table_name WHERE col2 = 'value2';

6. 索引列参与计算

如果索引列参与了计算,MySQL 无法直接使用索引。

sql 复制代码
-- 假设 price 列有索引,以下查询索引会失效
SELECT * FROM products WHERE price + 10 < 100;

可以将查询改写为不包含索引列计算的形式:

sql 复制代码
SELECT * FROM products WHERE price < 90;

7. IS NULL 和 IS NOT NULL 部分情况

对于索引列使用 IS NULLIS NOT NULL,在某些情况下可能会导致索引失效。不过,在 InnoDB 存储引擎中,对于 IS NULL 是可以使用索引的,但 IS NOT NULL 不一定能使用索引,具体取决于数据分布。

sql 复制代码
-- 以下查询在某些情况下可能索引失效
SELECT * FROM users WHERE email IS NOT NULL;

8. 数据分布不均匀

如果索引列的数据分布不均匀,例如大部分数据集中在少数几个值上,MySQL 可能会认为使用索引的成本较高,从而选择全表扫描。

例如,在一个 gender 列上创建了索引,该列只有 'male''female' 两个值,且分布严重不均衡,此时 MySQL 可能会选择全表扫描。

9. 索引被禁用或损坏

如果索引被手动禁用或者索引文件损坏,也会导致索引无法使用。可以通过 SHOW INDEX 查看索引状态,使用 REPAIR TABLE 修复损坏的索引。

sql执行全流程

MySQL 语句的执行过程是一个多阶段的复杂流程,涉及语法解析、优化、执行引擎等多个模块的协作。以下是 一条 SQL 语句从客户端发起到返回结果的全过程 ,以 SELECT * FROM users WHERE id = 1 为例:


一、连接阶段

  1. 建立连接

    • 客户端通过 TCP/IPSocket 协议与 MySQL 服务器建立连接。
    • MySQL 通过线程池管理连接(每个连接对应一个线程)。
    • 验证用户名、密码和权限。
  2. 接收 SQL 语句

    • 客户端将 SQL 语句发送到 MySQL 服务器。
    • 服务器将 SQL 语句存储在「网络接收缓冲区」中。

二、解析与预处理

  1. 查询缓存(MySQL 8.0 已移除)

    • (仅适用于旧版本)检查缓存中是否有完全相同的 SQL 语句及结果。
    • 若命中缓存,直接返回结果;否则继续执行。
  2. 词法分析 & 语法分析

    • 词法分析 :将 SQL 语句拆解为「关键字、表名、列名、操作符」等 Token
    • 语法分析 :验证 SQL 是否符合 MySQL 语法规则(如关键字顺序、括号匹配)。
    • 若语法错误,返回错误信息(如 ERROR 1064)。
  3. 语义分析

    • 验证表名、列名是否存在,用户是否有权限访问。
    • 检查 WHERE 条件中的列是否存在,数据类型是否匹配。

三、优化阶段

  1. 生成执行计划

    • 优化器(Optimizer)分析所有可能的执行路径,选择「成本最低」的执行计划。
    • 关键决策
      • 使用哪个索引(或全表扫描)。
      • JOIN 表的顺序(如果涉及多表查询)。
      • WHERE 条件的处理顺序。
  2. 优化器工作流程

    • 统计信息 :基于表的 rowsindex cardinality 等元数据估算不同执行计划的成本。
    • 成本模型 :计算磁盘 I/O、CPU 消耗、内存占用等成本。
    • 示例 :对 WHERE id = 1,优化器可能选择 PRIMARY 索引(如果 id 是主键)。

四、执行阶段

  1. 执行引擎

    • 执行器(Executor)根据优化器生成的执行计划,调用存储引擎接口读取数据。
    • 关键步骤
      • 打开表,获取表的元数据(如存储引擎类型)。
      • 调用存储引擎的索引查询接口(如 InnoDBindex_read)。
  2. 存储引擎处理(以 InnoDB 为例)

    • 索引查找 :通过 B+ 树索引定位到 id=1 的记录。
      • 若使用主键索引,直接找到数据页。
      • 若使用二级索引,需回表查询主键索引。
    • 事务与锁
      • 若在事务中,根据隔离级别加锁(如行锁、间隙锁)。
      • 保证事务的 ACID 特性(通过 undo logredo log)。
  3. 返回结果

    • 存储引擎将符合条件的记录返回给执行器。
    • 执行器将结果集放入「结果集缓冲区」。
    • 通过网络协议将结果返回客户端。

五、日志与事务(扩展)

  1. 日志模块

    • BinlogServer 层):记录逻辑操作(用于主从复制、数据恢复)。
    • Redo LogInnoDB):记录物理页修改,保证崩溃恢复。
    • Undo LogInnoDB):记录事务前的数据版本,用于回滚和 MVCC
  2. 事务提交

    • SQL 是更新操作(如 UPDATE),需写入 redo logbinlog
    • 通过两阶段提交(2PC)保证日志一致性。

六、关键流程图

plaintext 复制代码
客户端 → 建立连接 → 解析SQL → 优化器 → 执行引擎 → 存储引擎 → 返回结果
           │          │          │          │          │
          权限验证     语法检查     成本计算     调用接口     索引/行锁

七、性能优化点

  1. 减少解析时间
    • 避免频繁发送短 SQL,可使用预编译语句(Prepared Statement)。
  2. 优化执行计划
    • 更新统计信息:ANALYZE TABLE
    • 使用 FORCE INDEX 强制指定索引(慎用)。
  3. 减少磁盘 I/O
    • 通过索引减少扫描的数据量。
    • 调整 innodb_buffer_pool_size 提高缓存命中率。

通过理解 SQL 执行的全过程,可以更高效地优化查询性能和排查问题(如使用 EXPLAIN 分析执行计划)。

相关推荐
AI小白的Python之路11 分钟前
数据结构与算法-排序
数据结构·算法·排序算法
aneasystone本尊17 分钟前
学习 Coze Studio 的工作流执行逻辑
人工智能
DashVector20 分钟前
如何通过Java SDK检索Doc
后端·算法·架构
aneasystone本尊26 分钟前
再学 Coze Studio 的智能体执行逻辑
人工智能
苏婳66626 分钟前
【最新版】怎么下载mysqlclient并成功安装?
数据库·python·mysql
zzz93327 分钟前
transformer实战——mask
算法
xuanwuziyou28 分钟前
LangChain 多任务应用开发
人工智能·langchain
用户20187928316732 分钟前
Binder 同应用内(本地)通信是否存在 1MB 大小限制?
android
一条上岸小咸鱼1 小时前
Kotlin 基本数据类型(四):String
android·前端·kotlin
新智元1 小时前
一句话,性能暴涨 49%!马里兰 MIT 等力作:Prompt 才是大模型终极武器
人工智能·openai