目录
[1.1 索引的定义](#1.1 索引的定义)
[1.2 索引的核心作用](#1.2 索引的核心作用)
[1.3 索引的副作用](#1.3 索引的副作用)
[2.1 优先为高频查询字段创建索引](#2.1 优先为高频查询字段创建索引)
[2.2 避免为低基数字段创建索引](#2.2 避免为低基数字段创建索引)
[2.3 合理设计联合索引:遵循"最左前缀原则"](#2.3 合理设计联合索引:遵循“最左前缀原则”)
[2.4 避免创建冗余索引](#2.4 避免创建冗余索引)
[2.5 不为NULL值过多的字段创建索引](#2.5 不为NULL值过多的字段创建索引)
[3.1 主键索引(PRIMARY KEY)](#3.1 主键索引(PRIMARY KEY))
[3.2 唯一索引(UNIQUE)](#3.2 唯一索引(UNIQUE))
[3.3 普通索引(INDEX)](#3.3 普通索引(INDEX))
[3.4 联合索引(Composite Index)](#3.4 联合索引(Composite Index))
[3.5 全文索引(FULLTEXT)](#3.5 全文索引(FULLTEXT))
[4.1 查看索引](#4.1 查看索引)
[4.2 分析索引使用情况](#4.2 分析索引使用情况)
[4.3 索引维护:删除无效索引](#4.3 索引维护:删除无效索引)
[5.1 事务的定义](#5.1 事务的定义)
[5.2 事务的四大特性(ACID)](#5.2 事务的四大特性(ACID))
[5.3 事务的执行流程](#5.3 事务的执行流程)
[5.4 事务的隔离级别](#5.4 事务的隔离级别)
前言
在MySQL数据库的日常使用中,索引和事务是两个绕不开的核心概念。索引关乎查询效率,直接影响系统的响应速度;事务则保障数据一致性,是业务可靠性的基石。今天,我们就从基础到实践,全面梳理MySQL索引与事务的关键知识,帮你打通从理论到应用的"任督二脉"。
一、数据库索引基础:什么是索引,为何需要它?
1.1 索引的定义
索引就像图书的"目录",是数据库表中一列或多列值的排序结构,用于快速定位满足查询条件的数据行。没有索引时,MySQL查询数据需要执行"全表扫描"------逐行遍历表中所有数据,直到找到目标结果;而有了索引,就能通过索引结构直接定位到数据所在的物理位置,大幅减少数据扫描量。
1.2 索引的核心作用
-
提升查询效率:这是索引最核心的价值,尤其在大数据量场景下,全表扫描和索引查询的效率差距可能达千倍以上。例如,一张百万级数据的用户表,查询"用户ID=10086"的记录,全表扫描可能需要遍历数万行,而主键索引查询只需1-3次IO操作。
-
加速排序与分组:当查询包含ORDER BY、GROUP BY等子句时,若索引的排序顺序与查询的排序/分组顺序一致,MySQL可直接利用索引的有序性避免额外的排序操作,降低CPU开销。
1.3 索引的副作用
索引并非"越多越好",它在带来优势的同时也存在副作用,需理性使用:
-
占用额外存储空间:索引是独立的物理结构,会占用一定的磁盘空间。例如,一张数据量为1GB的表,其索引可能占用200-500MB的存储空间。
-
降低写操作效率:当执行INSERT、UPDATE、DELETE等写操作时,MySQL不仅要修改表数据,还需同步更新对应的索引结构(如平衡树的调整),导致写操作耗时增加。
二、索引创建原则与策略:避免无效索引
创建索引的核心原则是"按需创建"------只为高频查询字段创建索引,同时避免冗余和无效索引。具体策略如下:
2.1 优先为高频查询字段创建索引
重点关注WHERE子句中频繁出现的"查询条件字段"、JOIN子句中的"关联字段"以及ORDER BY/GROUP BY中的"排序/分组字段"。例如,电商系统中"订单表"的"用户ID"(关联查询)、"订单状态"(高频筛选)、"创建时间"(排序查询)都是优先创建索引的字段。
2.2 避免为低基数字段创建索引
"基数"指字段中不同值的数量占总记录数的比例。基数越低,索引的筛选效果越差。例如,"性别"字段只有"男""女"两个值,基数极低,使用索引查询时,可能仍需扫描大量数据,效率甚至不如全表扫描,因此不建议创建索引。
2.3 合理设计联合索引:遵循"最左前缀原则"
当查询条件涉及多个字段时,创建联合索引比单独创建多个单列索引更高效(减少索引数量,降低维护成本)。但联合索引的使用需遵循"最左前缀原则"------查询条件必须包含联合索引的第一个字段,索引才能生效。
示例:为"订单表(order_id, user_id, create_time)"创建联合索引(user_id, create_time),则:
-
有效查询:WHERE user_id=100 AND create_time>'2024-01-01'(包含最左前缀user_id);
-
无效查询:WHERE create_time>'2024-01-01'(不包含最左前缀,索引失效)。
联合索引字段顺序建议:将基数高的字段放在前面,提升筛选效率;将频繁用于排序的字段放在后面,匹配排序需求。
2.4 避免创建冗余索引
冗余索引指多个索引的功能存在重叠,例如:创建了联合索引(a, b)后,再单独创建索引(a)就是冗余的------因为联合索引的最左前缀(a)已具备单独索引(a)的功能。冗余索引会增加存储开销和写操作耗时,需及时清理。
2.5 不为NULL值过多的字段创建索引
若字段中NULL值占比极高,索引对该字段的筛选效果会大打折扣,因为索引无法有效区分大量的NULL值,此时不建议创建索引。
三、索引类型详解:不同场景选对索引
MySQL支持多种索引类型,不同类型的索引适用场景不同,需根据业务需求选择。常见索引类型如下:
3.1 主键索引(PRIMARY KEY)
主键索引是表的"唯一标识",用于唯一确定一条记录,每张表只能有一个主键索引,且主键字段的值不能为NULL。MySQL默认会为主键字段创建主键索引,其底层采用B+树结构,查询效率极高。
示例:创建表时指定主键索引:
sql
CREATE TABLE user (
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
);
3.2 唯一索引(UNIQUE)
唯一索引用于保证字段的值"唯一不重复"(允许NULL值,且多个NULL值不视为重复),一张表可创建多个唯一索引。常用于需要唯一约束的字段,如"用户名""手机号"等。
示例:创建唯一索引:
sql
CREATE TABLE user (
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
UNIQUE INDEX idx_username (username)
);
3.3 普通索引(INDEX)
普通索引是最基础的索引类型,无唯一约束,仅用于提升查询效率,一张表可创建多个普通索引。适用于高频查询但无需唯一约束的字段,如"订单状态""商品分类ID"等。
示例:创建普通索引:
sql
ALTER TABLE `order` ADD INDEX `idx_order_status` (`order_status`);
3.4 联合索引(Composite Index)
联合索引是基于多个字段创建的索引,如(a, b, c),其生效依赖"最左前缀原则",适用于多字段组合查询的场景。前文已详细说明,此处不再赘述。
示例:创建联合索引:
sql
ALTER TABLE `order` ADD INDEX `idx_user_create_time` (`user_id`, `create_time`);
3.5 全文索引(FULLTEXT)
全文索引用于"文本内容的模糊匹配",如文章标题、内容的关键词搜索,仅支持CHAR、VARCHAR、TEXT等文本类型字段。与LIKE '%关键词%'的全模糊匹配相比,全文索引的查询效率更高,且支持关键词分词。
注意:MySQL5.6及以上版本支持InnoDB引擎的全文索引,之前仅支持MyISAM引擎。
示例:创建全文索引并查询:
创建全文索引
sql
ALTER TABLE article ADD FULLTEXT INDEX idx_article_content (content);
全文检索查询
sql
SELECT * FROM article WHERE MATCH(content) AGAINST('MySQL 索引');
四、索引的查看与维护:让索引持续高效
创建索引后,需定期查看索引状态、分析索引使用情况,并进行必要的维护,避免无效索引占用资源。
4.1 查看索引
通过以下SQL语句可查看表中的所有索引信息:
sql
-- 方式1:查看表结构,包含索引信息
DESC user;
pgsql
-- 方式2:详细查看索引信息(推荐)
SHOW INDEX FROM user;
pgsql
-- 方式3:通过 INFORMATION_SCHEMA 查看
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'user';
4.2 分析索引使用情况
MySQL提供了EXPLAIN关键字,用于分析查询语句的执行计划,判断索引是否生效、是否存在全表扫描等问题。
示例:分析查询语句的索引使用情况:
sql
EXPLAIN SELECT * FROM `order` WHERE user_id=100 AND create_time>'2024-01-01';
关键查看type(索引类型,如ref、range表示索引生效,ALL表示全表扫描)和key(实际使用的索引名称,为NULL表示未使用索引)字段。
4.3 索引维护:删除无效索引
对于长期未使用、冗余或低效的索引,需及时删除,减少存储开销和写操作压力。删除索引的SQL语句如下:
sql
ALTER TABLE user DROP INDEX idx_username;
注意:删除索引前需确认该索引无业务依赖,避免影响查询效率。
五、MySQL事务基础:保障数据一致性的核心
在实际业务中,很多操作需要"原子性"执行,例如"转账"------从A账户扣钱和给B账户加钱,必须同时成功或同时失败,否则会出现数据不一致。事务就是为解决这类问题而生的。
5.1 事务的定义
事务是一组不可分割的SQL执行单元,这组SQL要么全部执行成功,要么全部执行失败,不存在"部分成功"的情况。
5.2 事务的四大特性(ACID)
ACID是事务的核心特性,也是判断事务是否可靠的标准:
-
原子性(Atomicity):事务是一个"原子"操作单元,要么全执行,要么全回滚。例如转账时,若扣钱成功后加钱失败,事务会回滚到扣钱前的状态,确保数据一致。
-
一致性(Consistency):事务执行前后,数据的完整性约束(如主键唯一、外键关联、字段非空等)保持一致。例如转账前A和B的总余额为1000元,事务执行后总余额仍为1000元。
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行结果不会被其他事务干扰,每个事务都像在独立执行。
-
持久性(Durability):事务执行成功后,对数据的修改会永久保存到磁盘,即使数据库崩溃,数据也不会丢失。
5.3 事务的执行流程
MySQL中,事务的执行需通过以下语句控制(默认情况下,MySQL为"自动提交"模式,即每条SQL语句都是一个独立事务,需手动关闭自动提交):
sql
-- 关闭自动提交(开启手动事务模式)
SET autocommit = 0;
-- 显式开始事务(明确事务边界)
START TRANSACTION;
-- 执行转账操作:A账户扣款100元
UPDATE account SET balance = balance - 100 WHERE id = 1;
-- 执行转账操作:B账户收款100元
UPDATE account SET balance = balance + 100 WHERE id = 2;
-- 验证业务规则(可选)
-- 例如检查A账户余额是否充足
SELECT balance INTO @current_balance FROM account WHERE id = 1;
IF @current_balance < 0 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
-- 恢复自动提交模式(可选)
SET autocommit = 1;
5.4 事务的隔离级别
事务的隔离性通过"隔离级别"控制,不同隔离级别对应不同的并发问题解决能力。MySQL支持四种隔离级别(从低到高):
-
读未提交(Read Uncommitted):最低级别,允许读取其他事务未提交的修改。可能出现"脏读"(读取到未提交的无效数据)。
-
读已提交(Read Committed):允许读取其他事务已提交的修改,解决"脏读"问题,但可能出现"不可重复读"(同一事务内多次读取同一数据,结果不一致)。MySQL默认隔离级别。
-
可重复读(Repeatable Read):同一事务内多次读取同一数据,结果一致,解决"不可重复读"问题,但可能出现"幻读"(同一事务内多次查询同一条件,结果行数不一致)。InnoDB引擎通过"MVCC(多版本并发控制)"机制解决了幻读问题。
-
串行化(Serializable):最高级别,事务串行执行,避免所有并发问题,但效率极低,适用于数据一致性要求极高的场景(如金融核心交易)。
查看和设置隔离级别的SQL:
sql
-- 查看当前事务隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别为READ COMMITTED(仅对当前会话生效)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
总结
索引和事务是MySQL性能优化和数据一致性保障的核心。索引的关键在于"按需创建、合理设计",通过避免冗余索引、遵循最左前缀原则等策略提升查询效率;事务的核心在于理解ACID特性和隔离级别,根据业务场景选择合适的隔离级别,通过手动事务控制确保数据一致性。
在实际开发中,需结合业务需求平衡索引的查询效率和写操作开销,同时通过事务隔离级别和手动事务控制,在并发性能和数据一致性之间找到最佳平衡点。希望本文能帮你扎实掌握MySQL索引与事务的核心知识,助力业务系统更高效、更可靠!