MySQL索引与事物
目录
一:MySQL索引介绍
1.索引概述
2.索引作用
3.索引的分类
关键区别
(1)普通索引
(2)唯一索引
(3)主键索引
(4)组合索引(最左前缀)
4.全文索引(FULLTEXT)
(1) 基本概念
(2) 版本与引擎支持
5.创建索引的原则依据
6.查看索引
7.删除索引
二:MySQL事务
1. 事务的基本概念
2. 事务的ACID特性
3. 事务的隔离级别
(1)用 BEGIN,ROLLBACK,COMMIT 来实现
(2)直接用 SET 来改变 MySQL 的自动提交模式
一:MySQL索引介绍
索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址。在数据十分庞大的时候,索引可以大大加快查询的速度。这是因为使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据。索引的作用类似于图书的目录,可以根据目录中的页码快速找到所需的内容。
1.索引概述
主题 | 描述 |
---|---|
索引概述 | 索引是对记录集的多个字段进行排序的方法,可以提高数据检索效率。 |
数据存储 | 数据以数据块的形式保存在磁盘上,数据块包含数据部分和指向下一个数据块的指针,不需要连续存储。 |
无序字段搜索 | 在无序字段上搜索需要线性搜索(Linear Search),平均访问 N/2N/2 个数据块。 |
有序字段搜索 | 在有序字段上可以运用二分查找(Binary Search),仅需访问 log2(N)log2(N) 个数据块。 |
索引作用 | 索引通过创建排序的数据结构(包含字段值和指针),允许二分查找,显著提高查询性能。 |
索引副作用 | 索引需要额外的磁盘空间,尤其是多个字段建立索引时,可能占用大量空间并达到文件系统大小限制。 |
MyISAM引擎 | MyISAM引擎将索引统一保存在一张表中,进一步增加磁盘空间的使用。 |
2.索引作用
在索引列上,除了上面提到的有序查找之外,数据库利用各种各样的快速定位技术,能够大大提高查询效率。特别是当数据量非常大,查询涉及多个表时,使用索引往往能使查询速度加快成千上万倍。
例如,有 3个未索引的表 t1、t2、t3,分别只包含列 c1、c2、c3,每个表分别含有 1000 行数据组成,均为 1~1000 的数值,查找对应值相等行的查询如下所示。
此查询结果应该为1000行,每行包含3个相等的值。在无索引的情况下处理此查询,必须寻找3个表所有的组合,以便得出与WHERE子句相配的那些行。而可能的组合数目为 1000x1000x1000(十亿),显然查询将会非常慢。
如果对每个表进行索引,就能极大地加速查询进程,,利用索引的查询处理如下:
从表 t1 中选择第一行,查看此行所包含的数据。
使用表 t2 上的索引,直接定位 t2 中与 t1 的值匹配的行。同理,利用表 t3上的索引,直接定位 t3 中与 t1的值匹配的行。
扫描表 t1 的下一行并重复前面的过程,直到遍历 t1中所有的行。
在此情形下,仍然对表 t1 执行了一个完全扫描,但能够在表 t2 和 t3 上进行索引查找直接取出这些表中的行,比未用索引时要快一百万倍。
利用索引,MySQL 加速了 WHERE 子句满足条件行的搜索,而在多表连接查询时、在执行连接时加快了与其他表中的行匹配的速度。
类别 | 优点 | 缺点 |
---|---|---|
查询性能 | 大幅提高数据检索速度,尤其是对有序字段使用二分查找(时间复杂度 O(logN)O(logN))。 | 索引本身占用存储空间,增加数据库文件大小。 |
排序优化 | 加速 ORDER BY 、GROUP BY 等排序操作。 | 索引需要维护,数据增删改(INSERT /DELETE /UPDATE )时性能会降低。 |
唯一性约束 | 唯一索引可保证字段值的唯一性(如主键)。 | 过多的索引会增加写操作的开销,影响写入性能。 |
覆盖索引 | 若查询仅涉及索引字段,可避免回表(直接从索引获取数据,减少 I/O)。 | 索引需要定期维护(如重建、优化),否则可能产生碎片,降低效率。 |
连接优化 | 加速表连接(JOIN )操作,尤其是外键字段的索引。 | 不合理的索引设计(如低选择性字段)可能无法提升性能,反而浪费资源。 |
锁竞争 | 减少全表扫描,降低锁冲突概率(如 SELECT 操作锁定更少数据)。 | 某些索引类型(如哈希索引)不支持范围查询或排序。 |
3.索引的分类
分类角度 | 索引类型 | 描述 | 特点 |
---|---|---|---|
物理存储 | 聚簇索引 | 数据行的物理存储顺序与索引顺序一致(如InnoDB的主键索引)。 | - 一个表只能有一个聚簇索引。 - 适合范围查询,减少I/O操作。 |
非聚簇索引 | 索引顺序与数据物理存储顺序无关(如MyISAM的索引)。 | - 一个表可有多个非聚簇索引。 - 需回表查询数据,单行检索更快。 | |
逻辑功能 | 普通索引 | 最基本的索引类型,无唯一性约束。 | - 允许重复值和NULL。 - 仅加速查询。 |
唯一索引 | 索引列的值必须唯一,但允许NULL(可多次出现)。 | - 保证数据唯一性。 - 可用于避免重复录入。 | |
主键索引 | 特殊的唯一索引,不允许NULL,且一个表只能有一个。 | - 默认聚簇索引(InnoDB)。 - 标识行的唯一性。 | |
组合索引 | 对多个列联合建立的索引(如 INDEX(col1, col2) )。 | - 遵循最左前缀原则。 - 减少单列索引开销,优化多条件查询。 | |
全文索引 | 针对文本内容的分词索引(如 FULLTEXT ),支持模糊搜索。 | - 仅适用于MyISAM/InnoDB(5.6+)。 - 适合大文本字段(如文章搜索)。 |
关键区别
-
聚簇索引:数据即索引(如InnoDB主键),非聚簇索引:索引与数据分离(如MyISAM)。
-
唯一索引 vs 主键索引:主键不允许NULL,且是表的唯一标识;唯一索引允许NULL(但NULL可重复)。
-
组合索引:查询需命中最左列(如
INDEX(a,b)
需条件包含a
才能生效)。
(1)普通索引
特性 | 说明 |
---|---|
定义 | 最基本的索引类型,无任何唯一性约束,允许重复值和 NULL 。 |
作用 | 加速查询条件(WHERE )、排序(ORDER BY )和连接(JOIN )操作。 |
前缀索引 | 可指定列的前 length 个字符作为索引(节省空间,但可能降低区分度)。 |
适用列类型 | 适用于 CHAR 、VARCHAR 、INT 等类型;BLOB /TEXT 必须用前缀索引。 |
最大长度限制 | - 默认上限:255 字节(MyISAM/InnoDB 为 1000 字节)。 - 超长时需用前缀索引。 |
直接创建索引:
修改表结构的方式添加索引:
创建表结构时,同时创建索引:
(2)唯一索引
特性 | 说明 |
---|---|
定义 | 索引列的值必须唯一,但允许包含 NULL 值(NULL 可重复出现)。 |
与主键索引的区别 | - 主键索引不允许 NULL ,唯一索引允许。- 一个表只能有一个主键,但可以有多个唯一索引。 |
组合唯一索引 | 如果是多列组合索引,则列值的组合必须唯一(单列可重复)。 |
创建方式 | 1. 直接创建:CREATE UNIQUE INDEX 2. 修改表结构: ALTER TABLE ADD UNIQUE 3. 建表时定义 |
适用场景 | - 避免数据重复(如用户名、邮箱、手机号等)。 - 需要唯一性约束但允许 NULL 的字段。 |
创建唯一索引:
修改表结构的方式添加唯一索引:
创建表的时候同时创建唯一索引:
(3)主键索引
特性 | 说明 |
---|---|
定义 | 特殊的唯一索引,用于唯一标识表中的每一行数据,不允许 NULL 值。 |
唯一性 | 一个表只能有一个主键索引,且主键列的值必须唯一。 |
约束 | 自动创建聚簇索引(InnoDB),物理存储顺序与主键顺序一致。 |
创建方式 | 通常在建表时定义,也可通过 ALTER TABLE 添加。 |
适用场景 | 需要唯一标识每一行数据的列(如用户ID、订单号等)。 |
与唯一索引的区别
对比项 | 主键索引 | 唯一索引 |
---|---|---|
数量限制 | 一个表只能有一个。 | 一个表可以有多个。 |
NULL 值 | 不允许。 | 允许(但 NULL 可重复)。 |
用途 | 标识行唯一性。 | 确保字段值唯一(非标识用途)。 |
(4)组合索引(最左前缀)
平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取MySQL 的效率,就要考虑建立组合索引。在组合索引的创建中,有两种场景,即为单列索引和多列索引。下面通过一个场景来具体说明单列索引和多列索引。
在一个 user 用户表中,有 name,age,sex 三个字段,分别分三次建立了INDEX 普通索引。那么在select*from user where name =AND age =AND sex=’’;数据査询语句中就会分别检索三条索引,虽然扫描效率有所提升,但却还未达到最优。这个时候就需要使用到组合索引(即多列索引),如下所示。
在 MySQL 中,有一个知识点叫最左原则。下面的 select 语句的 where 条件是依次从左往右执行的。
若使用的是组合索引 index user(name,age,sex)。在查询中,name、age、sex的顺序必须如组合索引中一致排序,否则索引将不会生效,例如:
如果采用“select *from user where age=‘’AND name =‘’ AND sex=‘’;”查询方式,这条组合索引将无效化,所以一般在建立索引时,要先想好相应的查询业务,尽量避免虽然有索引,但是使用不上的问题。
4.全文索引(FULLTEXT)
(1) 基本概念
-
定义:专门用于对文本内容(
CHAR
/VARCHAR
/TEXT
)进行分词检索的索引类型,支持自然语言搜索和布尔搜索。 -
适用场景:大段文本的模糊匹配(如文章搜索、商品描述搜索)。
(2) 版本与引擎支持
版本/引擎 | 支持情况 |
---|---|
MySQL < 5.6 | 仅 MyISAM 表支持全文索引。 |
MySQL ≥ 5.6 | InnoDB 和 MyISAM 均支持全文索引。 |
其他存储引擎 | MEMORY、NDB 等不支持。 |
创建表的全文索引:
修改表结构添加全文索引:
直接创建索引:
5.创建索引的原则依据
数据库建立索引的原则:
原则 | 说明 | 示例/注意事项 |
---|---|---|
查询 vs 增删改 | 索引适合读多写少的场景。写操作频繁的表需谨慎建索引。 | - 日志表频繁插入,避免过多索引。 - 用户表频繁查询,适合建索引。 |
高频 WHERE 条件 | 为频繁出现在 WHERE 、JOIN 、ORDER BY 中的字段建索引。 | SELECT * FROM orders WHERE user_id=100 → 为 user_id 建索引。 |
复合索引优先 | 联合索引比多个单列索引更高效,但需遵循最左前缀原则。 | INDEX(user_id, status) 可优化 WHERE user_id=1 AND status='paid' 。 |
小型表避坑 | 数据量小的表(如配置表)建索引可能降低性能(全表扫描更快)。 | 表数据 < 1000 行时,索引可能无收益。 |
低区分度字段慎用 | 对重复值多的字段(如性别、布尔值)建索引效果差。 | gender 字段仅有 'M'/'F',索引效率极低。 |
避免大类型索引 | 不要对 TEXT /BLOB 等大字段建完整索引,应使用前缀索引。 | INDEX(description(50)) 只索引前 50 字符。 |
索引建立的原则:
原则分类 | 具体原则 | 说明及示例 |
---|---|---|
索引的必要性 | 在经常用作过滤器的字段上建立索引 | 如 WHERE status='active' 中的 status 字段应建索引。 |
在频繁进行 GROUP BY 、ORDER BY 的字段上建立索引 | 如 ORDER BY create_time 或 GROUP BY department_id 的字段。 | |
在不同值较少的字段上避免建立索引(如性别、布尔值) | 区分度低的字段(如 gender 只有 'M'/'F')建索引效果差。 | |
索引的避免 | 对经常存取的列避免建立索引 | 高频更新的列(如 last_login_time )建索引会增加写开销。 |
外键与连接优化 | 在用于连接的列(主键/外键)上建立索引 | 如 JOIN ON user.id = order.user_id 中的 user_id 字段。 |
复合索引设计 | 在经常存取的多个列上建立复合索引,顺序按使用频度确定 | 复合索引 (department_id, status) 需优先放高频字段 department_id 。 |
聚簇索引选择 | 默认使用非聚簇索引,但对唯一值适中且大范围查询的列考虑聚簇索引 | 如主键 id 或范围查询频繁的 create_date 。 |
性能权衡 | 索引的建立需基于查询分析和预测,平衡读写性能 | 通过 EXPLAIN 分析慢查询,避免过度索引导致写入性能下降。 |
-
复合索引顺序:
-
最左前缀原则:
INDEX(A, B, C)
可优化WHERE A=1 AND B=2
,但无法优化WHERE B=2
。 -
高频字段优先:将查询频率高的字段放在复合索引左侧。
-
-
聚簇索引适用场景:
-
列值唯一性适中(如日期范围)。
-
减少大范围查询的 I/O 操作(如
WHERE create_date BETWEEN '2023-01-01' AND '2023-12-31'
)。
-
-
索引维护:
-
定期删除未使用的索引(如
ALTER TABLE DROP INDEX idx_unused
)。 -
监控索引碎片化并重建(如
OPTIMIZE TABLE orders
)。
-
6.查看索引
MySQL 数据表索引已经创建好了,那么如何才能查看刚刚创建的索引?或者怎么去查看表内已经存在的索引?有以下两种查看当前索引的方式。
以 auth表为例,査看auth表的索引内容。
字段解析:
字段名 | 值(示例) | 说明 |
---|---|---|
Table | renyuan | 索引所属的表名。 |
Non_unique | 0 | 是否允许重复值: - 0 :唯一索引(如主键或唯一约束)。- 1 :普通索引。 |
Key_name | id | 索引的名称。此处为 id ,可能是主键索引。 |
Seq_in_index | 1 | 索引中列的序号(从1开始),复合索引时表示列的顺序。 |
Column_name | id | 索引对应的列名。 |
Collation | A | 排序规则: - A :升序(Ascending)。- D :降序。- NULL :未排序。 |
Cardinality | 0 | 索引中唯一值的估计数量(基数)。值越大,索引区分度越高。 注意: 0 可能是表无数据或统计未更新(可执行 ANALYZE TABLE renyuan 刷新)。 |
Sub_part | NULL | 前缀索引的长度(如 10 表示只索引前10个字符)。NULL 表示整列索引。 |
Packed | NULL | 是否压缩索引,一般未使用。 |
Null | 空 | 是否允许 NULL 值:- 空:不允许。 - YES :允许。 |
Index_type | BTREE | 索引类型: - BTREE :默认的B+树索引(支持范围查询)。- HASH :哈希索引(仅精确匹配)。 |
Comment | 空 | 索引注释(可选)。 |
Visible | YES | 索引是否对优化器可见(YES /NO )。 |
Expression | NULL | MySQL 8.0+ 支持的函数索引表达式(如 JSON 字段路径)。 |
7.删除索引
索引在创建之后,是会占用一定的磁盘空间的,因此表内如果有不再使用的索引从数据库性能方面考虑,最好是删除无用索引。索引的删除有如下两种方法。
DROP INDEX 索引名 ON 表名;
ALTER TABLE 表名 DROP INDEX 索引名;
添加索引:
删除索引:
二:MySQL事务
1. 事务的基本概念
-
定义:事务是一组原子性的SQL操作,要么全部成功,要么全部失败。
-
适用场景:需要保证数据完整性的复杂操作(如银行转账、订单支付)。
-
引擎支持:仅 InnoDB 引擎支持完整的事务特性(MyISAM不支持)。
2. 事务的ACID特性
特性 | 说明 | 示例 |
---|---|---|
原子性 | 事务中的操作要么全部成功,要么全部回滚。 | 转账时,A账户扣款和B账户入账必须同时成功或失败。 |
一致性 | 事务前后数据库状态必须符合业务规则(如余额不能为负)。 | 转账后,总金额(A+B)必须与转账前一致。 |
隔离性 | 并发事务之间互不干扰(通过隔离级别控制)。 | 事务A未提交时,事务B不应看到中间结果。 |
持久性 | 事务提交后,数据永久保存(即使系统崩溃)。 | 转账成功后的数据必须写入磁盘,断电不丢失。 |
3. 事务的隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
---|---|---|---|---|
读未提交 | ✅ 可能 | ✅ 可能 | ✅ 可能 | 最低隔离级别,性能高但数据一致性差。 |
读已提交 | ❌ 不可能 | ✅ 可能 | ✅ 可能 | 仅读取已提交的数据(Oracle默认)。 |
可重复读(默认) | ❌ 不可能 | ❌ 不可能 | ✅ 可能 | 同一事务内多次读取结果一致(MySQL InnoDB默认)。 |
串行化 | ❌ 不可能 | ❌ 不可能 | ❌ 不可能 | 最高隔离级别,强制事务串行执行,性能最低但一致性最强。 |
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行SQL 语句后就会马上执行COMMIT操作。因此要显式地开启一个事务必须使用命令BEGIN或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
事务控制语句包含:
命令 | 语法 | 作用 | 示例 |
---|---|---|---|
开启事务 | BEGIN; 或 START TRANSACTION; | 显式开始一个事务(关闭自动提交)。 | BEGIN; |
提交事务 | COMMIT; 或 COMMIT WORK; | 永久保存事务中的所有修改。 | COMMIT; |
回滚事务 | ROLLBACK; 或 ROLLBACK WORK; | 撤销事务中的所有未提交修改。 | ROLLBACK; |
设置保存点 | SAVEPOINT savepoint_name; | 在事务中创建标记点,支持部分回滚。 | SAVEPOINT sp1; |
回滚到保存点 | ROLLBACK TO savepoint_name; | 回滚到指定保存点(不影响保存点之前的操作)。 | ROLLBACK TO sp1; |
删除保存点 | RELEASE SAVEPOINT savepoint_name; | 删除已定义的保存点(若保存点不存在会报错)。 | RELEASE SAVEPOINT sp1; |
设置隔离级别 | SET TRANSACTION ISOLATION LEVEL level; | 设置当前会话或下一个事务的隔离级别(需在事务开始前设置)。 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
隔离级别 | 命令语法 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
读未提交 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | ✅ 可能 | ✅ 可能 | ✅ 可能 |
读已提交 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | ❌ 不可能 | ✅ 可能 | ✅ 可能 |
可重复读(默认) | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | ❌ 不可能 | ❌ 不可能 | ✅ 可能 |
串行化 | SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; | ❌ 不可能 | ❌ 不可能 | ❌ 不可能 |
MYSQL 事务处理主要有两种方法:
(1)用 BEGIN,ROLLBACK,COMMIT 来实现
BEGIN 开始一个事务
ROLLBACK事务回滚
COMMIT 事务确认
(2)直接用 SET 来改变 MySQL 的自动提交模式
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
以下是事务的示例: