MySQL事务和索引原理

article/2025/6/20 3:21:01

目录

1. MySQL事务原理

1.1. 事务的基本概念

1.2. 事务隔离的实现机制

1.3. 事务的启动方式

2. 索引的原理

2.1. 索引的作用

2.2. 索引常用模型及适用场景

2.3. InnoDB中的索引结构

2.4. 索引维护

2.5. 覆盖索引

2.6. 联合索引和最左缀原则

2.7. 索引下推


1. MySQL事务原理

1.1. 事务的基本概念

  • 补充内容见SQL本栏以前的SQL章节

事务的基本概念:

什么是事务?

  • 一组数据库操作,要么全部成功,要么全部失败,具有“原子性”。
  • 典型应用场景:银行转账操作,必须保证“减钱”和“加钱”一起完成。

事务的支持

  • MySQL 的事务支持是在 存储引擎层 实现的。
  • InnoDB 支持事务,MyISAM 不支持(这是 InnoDB 取代 MyISAM 的主要原因之一)。

ACID 中的 “I” —— 隔离性(Isolation)

什么是隔离性:

多个事务并发执行时,各自的操作不应相互干扰。

常见并发问题:

问题类型

说明

脏读

读取了另一个事务尚未提交的数据

不可重复读

同一事务中多次读取结果不一致

幻读

同一事务中读取到“新增或删除”的记录

SQL 标准隔离级别(由低到高):

隔离级别

特点

是否存在脏读

不可重复读

幻读

Read Uncommitted

可读未提交数据

✅ 是

✅ 是

✅ 是

Read Committed

只读已提交数据

❌ 否

✅ 是

✅ 是

Repeatable Read

可重复读(MySQL 默认)

❌ 否

❌ 否

✅ 是

Serializable

串行化(最安全)

❌ 否

❌ 否

❌ 否

  • MySQL 默认隔离级别是:Repeatable Read
  • Oracle 默认隔离级别是:Read Committed
  • 迁移时要注意设置一致:transaction-isolation = READ-COMMITTED

1.2. 事务隔离的实现机制

MVCC(多版本并发控制):

  • 每条记录在更新时会生成一条回滚记录。
  • 所有版本记录可通过回滚日志回溯。
  • 不同事务有不同的 read view(读取视图)。

示例:

值从 1 → 2 → 3 → 4,某个事务的 read view 可能还看到的是 1。

回滚日志的清理机制:

  • 系统会判断是否仍有事务需要旧的版本。
  • 当没有比当前回滚日志更早的事务存在时,可清理该日志。

避免使用长事务的原因

  1. 占用大量回滚日志(导致 ibdata 文件急剧膨胀)
  2. 锁资源占用,可能阻塞其他事务
  3. 历史版本维护成本高

MySQL 5.5 之前回滚日志无法自动回收,可能导致文件过大。

1.3. 事务的启动方式

  1. 自动模式:很多数据库系统(例如MySQL、PostgreSQL)默认处于自动事务模式。在这种模式下,每个SQL语句都被当作一个事务,并且会自动地启动、执行和提交。这种模式适合大多数的应用,因为它简单易用,但是可能会导致频繁的事务启动和提交,影响性能。
  2. 显式地启动事务:在显式事务模式下,你需要使用特定的SQL语句来启动事务,通常是BEGIN、START TRANSACTION等。在事务内,你可以执行多个SQL语句,并且通过COMMIT语句提交事务,或者使用ROLLBACK语句回滚事务。这种方式给予了你更多的控制权,可以在一个事务内执行多个操作,然后一次性地提交或回滚。
  3. 编程式启动事务:在应用程序中,特定的编程语言和数据库连接库(例如JDBC、Hibernate等)提供了编程式事务控制的能力。在这种方式下,你可以在代码中显式地启动、提交和回滚事务。这种方式通常用于需要更复杂事务逻辑的应用,例如需要多个数据库操作保持一致性的情况。

方式

描述

显式事务

BEGIN

/ START TRANSACTION

COMMIT

ROLLBACK

隐式事务

SET autocommit=0

:所有语句自动开启事务

推荐方式

使用显式事务 + SET autocommit=1

警惕意外长事务:

  • 有些客户端库默认执行 SET autocommit=0,若未手动提交,可能造成 隐式长事务
  • 推荐使用 COMMIT WORK AND CHAIN:执行提交后立即开启下一个事务。
  • 可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

2. 索引的原理

2.1. 索引的作用

本质上,索引是“用于加速数据检索的数据结构”。

  • 提升查询效率:加速 WHERE 条件、JOIN、ORDER BY、GROUP BY 等语句的执行。
  • 加速排序和分组:利用索引中的有序特性,减少排序计算成本。
  • 实现唯一性约束:例如主键索引保证数据唯一。
  • 辅助查询优化器选择执行计划

2.2. 索引常用模型及适用场景

模型

结构特点

优点

缺点

适用场景

哈希表

键值对映射(无序)

查询速度极快,O(1)

无序,不支持范围查询或排序

等值查询,如 id = 100

有序数组

连续内存中有序排列

二分查找快,适合范围查询

插入成本高(需整体移动)

静态数据、范围查找

搜索树

(如红黑树)

动态平衡树结构

插入/删除/查找复杂度 O(logN)

难以快速进行磁盘页访问优化

通用结构,适合内存存储

B+树

多叉平衡树,数据存在叶子节点

磁盘友好,支持范围查询

内存占用比哈希略高

数据库和文件系统中广泛使用

  • 查询频繁、数据量大 → ✅ B+树最适合。
  • 只做等值查询、数据可全部放内存 → ✅ 哈希表优先。
  • 插入频繁 → ❌ 避免用有序数组。
  • 数据静态、查找密集 → ✅ 有序数组也可考虑。

2.3. InnoDB中的索引结构

为什么用 B+ 树:

  • 磁盘访问效率高:每个节点存储多个键值对,I/O 次数少。
  • 范围查询友好:叶子节点通过指针串联,支持快速范围扫描。
  • 高度低:一般 2~3 层就能存储百万级数据。

B+ 树结构特点:

  • 所有值存储在叶子节点,非叶节点只做索引。
  • 叶子节点间通过链表连接,支持顺序访问。
  • 高度平衡,插入删除操作后自动维护平衡。

InnoDB 的索引类型:

索引类型

存储内容说明

特点

主键索引(聚簇索引)

叶子节点存储整行数据

索引就是数据,按主键有序

辅助索引(二级索引)

叶子节点存储主键值(不是整行)

需回表查询实际数据

  • 回表查询:通过辅助索引定位主键,再通过主键索引获取整行数据。

示例:

假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。

这个表的建表语句是:

mysql> create table T(
id int primary key, 
k int not null, 
name varchar(16),
index (k))engine=InnoDB;

表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下。

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。

  • 主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
  • 非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。

基于主键索引和普通索引的查询有什么区别?

  • 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
  • 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询

2.4. 索引维护

索引维护的概念:

索引维护是指在数据库执行 INSERT、DELETE、UPDATE 等写操作时,自动同步更新对应的索引结构,以保持数据和索引的一致性。

索引维护的基本过程:

操作类型

索引维护动作

说明

插入

在对应的索引结构中插入新记录的位置

B+ 树节点可能需要分裂或调整

删除

从索引中删除指定记录的键值

涉及节点合并或重平衡

更新

若更新字段被索引,等同于删除+插入

比仅更新值成本更高

  • 注意:更新非索引字段不会触发索引更新,但更新索引字段会引发一次**“删除旧记录 + 插入新记录”**的完整流程。

索引维护对性能的影响:

操作

对性能的影响

插入大量数据

索引频繁重构,耗时明显

批量更新索引列

成本高,建议避免大批量更新索引字段

删除操作

需判断是否触发合并,影响写入性能

太多冗余索引

每次写操作都需同步更新所有相关索引

优化建议:

  • 控制索引数量,仅对常用查询字段建立索引;
  • 批量插入或导入数据前,可暂时移除索引,导入后重建;
  • 避免频繁修改被索引字段,降低维护成本。

主键的选择:

主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

从性能和存储空间方面考量,自增主键往往是更合理的选择。

有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的:

  1. 只有一个索引;
  2. 该索引必须是唯一索引。

这就是典型的 KV 场景。

由于没有其他索引,所以也就不用考虑其他索引的叶子节点大小的问题。

这时候我们就要优先考虑上面提到的“尽量使用主键查询”原则,直接将这个索引设置为主键,可以避免每次查询需要搜索两棵树。

2.5. 覆盖索引

回表的概念:

回表(回表查询)是数据库查询优化器在执行查询时的一种策略。当查询的条件无法通过索引直接获取数据时,查询优化器会选择通过索引获取到的主键值,然后再根据这些主键值去主键索引中查找对应的数据,这个过程就叫做回表。

覆盖索引的定义:

如果查询所需要的字段都能在一个索引中直接获取,就不需要回表,这种索引称为 覆盖索引

优点:

  • 避免回表,减少树的访问次数
  • 提升查询性能,尤其在 高频请求 中表现明显。

示例:

SELECT ID FROM T WHERE k BETWEEN 3 AND 5;
  • 由于 ID 存储在索引 k(k) 中,不需要回表,形成覆盖索引。
  • 引擎层实际读取的是三条索引记录(R3~R5),但 Server 层认为扫描了 2 行(符合条件的2行)。

2.6. 联合索引和最左缀原则

联合索引概念:

联合索引是指在一个索引中包含多个列的索引。

联合索引的优势:

  • 支持多列联合查询加速:对于同时包含多个字段的查询,联合索引可以一次性命中多个字段,提高检索效率。
  • 支持最左前缀原则(见下),具备较强的索引复用能力。
  • 可用于覆盖索引,避免回表,提高性能。

最左前缀原则

查询语句中用到的字段必须从联合索引的最左边开始,连续匹配,才能使用索引。

例如,索引为 (a, b, c)

查询条件

能否使用索引?

原因

WHERE a = 1

✅ 是

匹配最左前缀 a

WHERE a = 1 AND b = 2

✅ 是

匹配 a, b

WHERE b = 2 AND a = 1

✅ 是

虽然顺序不同,但条件包含 a, b

WHERE b = 2

❌ 否

不满足最左字段 a,无法使用索引

WHERE a = 1 AND c = 3

✅ 部分

匹配了 a,但跳过了 b,c 无法参与索引

WHERE a LIKE '张%'

✅ 是

字符串最左前缀匹配也可以用索引

字段顺序设计原则:

1. 最常出现在查询条件中的字段放在前面(提高索引利用率)。

2. 区分度高的字段放前面(能快速缩小范围)。

3. 尽量减少冗余索引:

  • 如果有 (a, b) 联合索引,通常不需要再建 (a)。
  • 但如果经常单独用 b 查询,还需考虑是否加上 (b) 索引。

4. 考虑是否用于覆盖索引(被查询的字段尽量全部包含在索引中)。

2.7. 索引下推

索引下推的定义:

索引遍历过程中,直接在索引内部判断条件是否满足,提前过滤掉无效记录,减少回表次数

示例:

联合索引 (name, age),查询:

sql复制编辑
SELECT * FROM tuser WHERE name LIKE '张%' AND age=10 AND ismale=1;
  • 无索引下推:name 匹配后全部回表判断 age。
  • 有索引下推:在索引中先判断 age,再决定是否回表。
  • 回表次数显著减少,查询效率显著提升。

http://www.hkcw.cn/article/tduZnNPBZt.shtml

相关文章

第十一章 Java基础-继承

文章目录 1.继承来源2.继承特点3.子类能继承父类中哪些内容1.继承来源 是为了解决代码的重复冗余。

【11408学习记录】考研英语写作提分秘籍:2013真题邀请信精讲+万能模板套用技巧

邀请信 英语写作2013年考研英语(一)真题小作文题目分析写作思路第一段:第二段:锦囊妙句1:锦囊妙句2:锦囊妙句3:锦囊妙句5:锦囊妙句6:锦囊妙句9:锦囊妙句14&am…

汽车电子笔记之:有关汽车电子AUTOSAR的一些名词解释

目录 1、概述 2、基础概念 2.1、SPEM 2.2、SPEC 2.3、SIP包 2.4、SLP 2.5、HLP 2.6 、AUTOSAR方法论 2.6.1、ECU Extruct 2.6.2、ECU Configuration Values(EcuC) 2.6.3、Software Component Deion 2.6.4、Measurement and Calibration S…

ASP.NET Core OData 实践——Lesson8增删改查原始类型Property(C#)

大纲 支持的接口主要模型设计控制器设计数据源查询(GET)查询基础类型的原始类型属性查询基类类型Entity的基础类型属性的值查询基类类型Entity的派生类型属性的原始值 查询派生类型Entity的基础类型属性查询派生类型Entity的属性值查询派生类型Entity的派生类型属性的原始值 新…

PCIE之Lane Reserval通道out of oder调换顺序

参考:测量小百科 | PCIe通道位置翻转(Lane Reversal)技术 参考:PCIe学习笔记(3)链路初始化和训练_pcie 有序集 lane-CSDN博客 案例上都是按照x4或者x8交叉,对于x2也是有办法交叉的,如果4lane的顺序并不是…

LXQt修改开始菜单高亮

开始菜单红色高亮很难看 mkdir -p ~/.local/share/lxqt/palettes/ mkdir -p ~/.local/share/lxqt/themes/ cp /usr/share/lxqt/palettes/Dark ~/.local/share/lxqt/palettes/Darker cp -p /usr/share/lxqt/themes/dark ~/.local/share/lxqt/themes/darker lxqt-panel.qss L…

MIT 6.S081 2020 Lab6 Copy-on-Write Fork for xv6 个人全流程

文章目录 零、写在前面一、Implement copy-on write1.1 说明1.2 实现1.2.1 延迟复制与释放1.2.2 写时复制 零、写在前面 可以阅读下 《xv6 book》 的第五章中断和设备驱动。 问题 在 xv6 中,fork() 系统调用会将父进程的整个用户空间内存复制到子进程中。**如果父…

使用langchain实现RAG(检索增强生成)

概述 本文将从零开始实现一个langchain应用程序, 该应用支持读取pdf文档并embedding编码到Chroma数据库, 当用户提问时, 可以从网络搜索结果和本地向量数据库中收集数据, 传递给第三方LLM大模型, 所有使用到的工具完全免费 将使用如下技术或工具: python3.9langchainChroma …

力扣HOT100之动态规划:139. 单词拆分

这道题之前刷代码随想录的时候已经做过了,但是现在再做一遍还是不会,直接去看视频了。感觉这道题的dp数组很难想到,感觉做不出来也是情有可原吧。这道题目也是一个完全背包问题,字典里的单词就相当于物品,而字符串相当…

趋势直线指标

趋势直线副图和主图指标,旨在通过技术分析工具帮助交易者识别市场趋势和潜在的买卖点。 副图指标:基于KDJ指标的交易策略 1. RSV值计算: - RSV(未成熟随机值)反映了当前收盘价在过去一段时间内的相对位置。通过计算当前…

应急响应靶机-web3-知攻善防实验室

题目: 1.攻击者的两个IP地址 2.攻击者隐藏用户名称 3.三个攻击者留下的flag 密码:yj123456 解题: 1.攻击者的两个IP地址 一个可能是远程,D盾,404.php,192.168.75.129 找到远程连接相关的英文,1149代表远程连接成功…

前端-不对用户显示

这是steam的商店偏好设置界面,在没有被锁在国区的steam账号会有5个选项,而被锁在国区的账号只有3个选项,这里使用的技术手段仅仅在前端隐藏了这个其他两个按钮。 单击F12打开开发者模式 单击1处,找到这一行代码,可以看…

C++单调栈(递增、递减)

定义 先说单调栈的定义 单调栈,是指栈内数据逐步上升(一个比一个大),或逐步下降(一个比一个小)的栈,其并没有独立的代码,而是在stack的基础上加以限制及条件形成的。 比如&#x…

WIN11+CUDA11.8+VS2019配置BundleFusion

参考: BundleFusion:VS2019 2017 ,CUDA11.5,win11,Realsense D435i离线数据包跑通,环境搭建 - 知乎 Win10VS2017CUDA10.1环境下配置BundleFusion - 知乎 BundleFusionWIN11VS2019 CUDA11.7环境配置-CSDN博客 我的环境:Win 11…

【基于SpringBoot的图书购买系统】Redis中的数据以分页的形式展示:从配置到前后端交互的完整实现

引言 在当今互联网应用开发中,高性能和高并发已经成为系统设计的核心考量因素。Redis作为一款高性能的内存数据库,以其快速的读写速度、丰富的数据结构和灵活的扩展性,成为解决系统缓存、高并发访问等场景的首选技术之一。在图书管理系统中&…

Leetcode LCR 187. 破冰游戏

1.题目基本信息 1.1.题目描述 社团共有 num 位成员参与破冰游戏,编号为 0 ~ num-1。成员们按照编号顺序围绕圆桌而坐。社长抽取一个数字 target,从 0 号成员起开始计数,排在第 target 位的成员离开圆桌,且成员离开后从下一个成员…

任务20:实现各省份平均气温预测

任务描述 知识点: 时间序列分析 重 点: 指数平滑法Python连接数据库,更新数据 内 容: 读取所有省份各月的平均气温数据预测各省份下一年1-12月的气温,并存储到MySQL数据库 任务指导 1. 读取所有省份各月的平…

【Unity】AudioSource超过MaxDistance还是能听见

unity版本:2022.3.51f1c1 将SpatialBlend拉到1即可 或者这里改到0 Hearing audio outside max distance - #11 by wderstine - Questions & Answers - Unity Discussions

VulnStack|红日靶场——红队评估四

信息收集及漏洞利用 扫描跟kali处在同一网段的设备,找出目标IP arp-scan -l 扫描目标端口 nmap -p- -n -O -A -Pn -v -sV 192.168.126.154 3个端口上有web服务,分别对应三个漏洞环境 :2001——Struts2、2002——Tomcat、2003——phpMyAd…

在 RK3588 上通过 VSCode 远程开发配置指南

在 RK3588 上通过 VSCode 远程开发配置指南 RK3588 设备本身不具备可视化编程环境,但可以通过 VSCode 的 Remote - SSH 插件 实现远程代码编写与调试。以下是完整的配置流程。 一、连接 RK3588 1. 安装 Debian 系统 先在 RK3588 上安装 Debian 操作系统。 2. 安…