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 分析执行计划)。

相关推荐
WispX8881 小时前
【JVM】GC 常见问题
java·jvm·算法
cxr8282 小时前
基于变分推理与 Best‑of‑N 策略的元 Prompt 自动生成与优化框架
人工智能·提示词
安忘3 小时前
LeetCode-274.H 指数
算法·leetcode·职场和发展
xxxmmc3 小时前
Leetcode 160 Intersection of Two Linked Lists
算法·leetcode·双指针
练习两年半的工程师3 小时前
使用React和google gemini api 打造一个google gemini应用
javascript·人工智能·react.js
王的备忘录4 小时前
结合使用 OpenCV 和 TensorFlow进行图像识别处理
人工智能·opencv·tensorflow
VincentStory4 小时前
分享一个项目中遇到的一个算法题
android·算法
赛卡5 小时前
自动驾驶背后的数学:特征提取中的线性变换与非线性激活
人工智能·python·机器学习·自动驾驶·numpy
丶21365 小时前
【AI】深度学习与人工智能应用案例详解
人工智能·深度学习
八股文领域大手子5 小时前
Leetcode32 最长有效括号深度解析
java·数据库·redis·sql·mysql