MySQL索引与性能优化入门:让查询提速的秘密武器【MySQL系列】

news2025/6/3 20:46:47

本文将深入讲解 MySQL 索引的底层原理、常见类型、使用技巧,并结合 EXPLAIN 工具分析查询执行计划,配合慢查询日志识别瓶颈,逐步建立起系统的 MySQL 查询优化知识体系。适合有一定基础、希望在数据量增长或面试中脱颖而出的开发者阅读。


一、MySQL索引是什么?

1.1 索引的本质

索引是一种数据结构,其目的是提升数据库查询效率。它将表中的某些列值抽取出来,构建一个高效的查找结构(通常是 B+ 树),通过该结构定位数据的存储位置。

换句话说,索引是表数据的“加速器”。没有索引时,MySQL 只能做全表扫描;有索引时,可快速缩小查找范围。

1.2 索引的类比

  • 无索引:就像找一本书中某个词,必须逐页翻阅。
  • 有索引:像是查字典,有字母目录直接定位页码。

二、MySQL常见索引类型

2.1 主键索引(PRIMARY KEY)

每张表只能有一个主键索引,默认是聚簇索引。

2.2 唯一索引(UNIQUE)

保证字段值唯一,适合如邮箱、身份证号等字段。

2.3 普通索引(INDEX)

最基础的索引,无任何约束,只提升查询性能。

2.4 组合索引(Composite Index)

在多个列上创建的索引,遵循“最左前缀”原则。

2.5 全文索引(FULLTEXT)

用于全文搜索,支持自然语言分析。

2.6 空间索引(SPATIAL)

主要用于 GIS 地理信息类型字段。


三、索引底层原理:B+树结构详解

MySQL 的 InnoDB 存储引擎默认使用 B+ 树作为索引结构。

3.1 B+树特性

  • 所有数据都存储在叶子节点。
  • 非叶子节点只存储键值(索引项),不存储数据。
  • 所有叶子节点通过链表相连,方便区间查询。

3.2 聚簇索引 vs 非聚簇索引

  • 聚簇索引:主键索引,数据和索引存储在一起。
  • 二级索引(辅助索引):索引结构中存储的是主键的值,需要二次回表查询原始数据。

四、创建索引的最佳实践

4.1 如何选择索引列?

  • 用于 WHERE 子句过滤的字段
  • 用于 JOIN、ORDER BY、GROUP BY 的字段
  • 高基数(distinct 值多)的字段优先考虑

4.2 创建索引示例

-- 普通索引
CREATE INDEX idx_email ON users(email);

-- 唯一索引
CREATE UNIQUE INDEX idx_mobile ON users(mobile);

-- 组合索引
CREATE INDEX idx_multi ON orders(user_id, status);

4.3 删除索引

DROP INDEX idx_email ON users;

4.4 查看索引

SHOW INDEX FROM users;

五、查询优化利器:EXPLAIN 执行计划

5.1 基本使用

EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

5.2 关键字段解析

字段含义
id查询序列编号
select_type查询类型(SIMPLE、PRIMARY、SUBQUERY 等)
table当前访问的表
type连接类型(ALL、index、range、ref、const、eq_ref、NULL)
key使用的索引
rows预计扫描的行数
Extra额外信息,如"Using where"、“Using index”

5.3 type 字段详解

  • ALL:全表扫描(最差)
  • index:全索引扫描
  • range:范围扫描,如 BETWEEN、>、<
  • ref:使用非唯一索引查找
  • const:唯一索引等值查找,最多一行

5.4 案例:组合索引未命中

CREATE INDEX idx_user_status ON orders(user_id, status);

-- 命中索引
SELECT * FROM orders WHERE user_id = 123 AND status = 'paid';

-- 未命中组合索引
SELECT * FROM orders WHERE status = 'paid';

六、慢查询日志:发现性能瓶颈

6.1 开启慢查询日志

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1

6.2 查询慢日志内容

mysqldumpslow -s r -t 10 /var/log/mysql/mysql-slow.log

6.3 使用 pt-query-digest 分析慢查询

pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt

七、常见查询优化技巧

7.1 避免 SELECT *

明确列字段,避免读取不必要数据。

7.2 使用覆盖索引

查询所用字段全部在索引中,避免回表。

-- 创建覆盖索引
CREATE INDEX idx_name_age ON users(name, age);

-- 查询使用覆盖索引
SELECT name, age FROM users WHERE name = 'Tom';

7.3 避免在 WHERE 中对索引字段做函数操作

-- 不走索引
SELECT * FROM users WHERE DATE(create_time) = '2024-01-01';

-- 优化后
SELECT * FROM users WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02';

7.4 利用 LIMIT + 索引分页优化

-- 分页慢
SELECT * FROM users ORDER BY id LIMIT 10000, 10;

-- 延迟关联优化
SELECT * FROM users WHERE id > (SELECT id FROM users ORDER BY id LIMIT 10000, 1) LIMIT 10;

7.5 拆分大查询

将一次性操作百万数据的语句,拆分为批量处理:

DELETE FROM logs WHERE created_at < '2023-01-01' LIMIT 1000;

八、避免这些索引误区

  • 所有字段都建索引:浪费空间 + 写入变慢
  • 忽视组合索引顺序:需遵循最左前缀原则
  • 数据量小也加索引:小表加索引反而可能变慢
  • 高频更新字段建索引:更新频繁的字段不建议建索引

九、实践案例:优化百万级用户查询

9.1 初始场景

SELECT * FROM users WHERE email = 'abc@example.com';
  • 数据量:用户表 500 万条
  • 无索引:执行时间 > 3 秒

9.2 添加索引

CREATE INDEX idx_email ON users(email);

9.3 使用 EXPLAIN 检查

EXPLAIN SELECT * FROM users WHERE email = 'abc@example.com';
-- type: ref, key: idx_email, rows: 1
  • 查询时间降低至 < 10ms

本项目适用于后台管理系统、电商用户中心、SaaS 用户模块等场景,特别适合开发者进行实战演练与面试准备。


一、项目背景与需求概述

我们将构建一个基础版的用户管理系统,具备以下业务功能:

  • 用户注册与登录
  • 用户角色与权限分配
  • 日志记录与用户状态追踪
  • 多条件用户查询与分页

涉及的核心业务对象包括:用户、角色、权限、日志等。


二、数据库建模与表结构设计

2.1 实体关系图(ER图)简要说明

  • 一位用户可以拥有多个角色(多对多)
  • 一个角色可以拥有多个权限(多对多)
  • 用户与登录日志是一对多关系

2.2 用户表(users

CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50) NOT NULL UNIQUE,
  password VARCHAR(100) NOT NULL,
  email VARCHAR(100),
  status TINYINT DEFAULT 1 COMMENT '0:禁用, 1:启用',
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

2.3 角色表(roles

CREATE TABLE roles (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL UNIQUE,
  description VARCHAR(255)
);

2.4 权限表(permissions

CREATE TABLE permissions (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL UNIQUE,
  code VARCHAR(50) NOT NULL UNIQUE COMMENT '用于权限标识,如 user:view'
);

2.5 用户-角色关联表(user_role

CREATE TABLE user_role (
  user_id INT,
  role_id INT,
  PRIMARY KEY (user_id, role_id),
  FOREIGN KEY (user_id) REFERENCES users(id),
  FOREIGN KEY (role_id) REFERENCES roles(id)
);

2.6 角色-权限关联表(role_permission

CREATE TABLE role_permission (
  role_id INT,
  permission_id INT,
  PRIMARY KEY (role_id, permission_id),
  FOREIGN KEY (role_id) REFERENCES roles(id),
  FOREIGN KEY (permission_id) REFERENCES permissions(id)
);

2.7 登录日志表(login_logs

CREATE TABLE login_logs (
  id INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT,
  ip_address VARCHAR(45),
  login_time DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

三、数据初始化脚本

3.1 插入初始角色与权限

INSERT INTO roles(name, description) VALUES ('admin', '系统管理员'), ('user', '普通用户');

INSERT INTO permissions(name, code) VALUES
('查看用户', 'user:view'),
('新增用户', 'user:create'),
('删除用户', 'user:delete');

-- 分配权限给角色
INSERT INTO role_permission(role_id, permission_id) VALUES
(1, 1), (1, 2), (1, 3), -- admin 拥有全部权限
(2, 1);                 -- user 仅能查看用户

3.2 插入测试用户

INSERT INTO users(username, password, email) VALUES
('alice', 'hashed_pwd1', 'alice@example.com'),
('bob', 'hashed_pwd2', 'bob@example.com');

-- 分配角色
INSERT INTO user_role(user_id, role_id) VALUES
(1, 1), -- alice 为管理员
(2, 2); -- bob 为普通用户

四、典型查询场景实现

4.1 查询所有启用用户及其角色

SELECT u.id, u.username, r.name AS role
FROM users u
JOIN user_role ur ON u.id = ur.user_id
JOIN roles r ON ur.role_id = r.id
WHERE u.status = 1;

4.2 查询某用户拥有的所有权限

SELECT p.name, p.code
FROM users u
JOIN user_role ur ON u.id = ur.user_id
JOIN role_permission rp ON ur.role_id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE u.username = 'alice';

4.3 查询最近7天登录日志

SELECT u.username, l.ip_address, l.login_time
FROM login_logs l
JOIN users u ON l.user_id = u.id
WHERE l.login_time >= NOW() - INTERVAL 7 DAY
ORDER BY l.login_time DESC;

4.4 用户分页查询(带关键字搜索)

SELECT *
FROM users
WHERE username LIKE '%bob%'
ORDER BY created_at DESC
LIMIT 0, 10;

五、事务控制与一致性保障

在角色授权或用户注册等业务流程中,可以使用事务来确保数据完整性。

5.1 注册用户 + 分配默认角色(事务)

START TRANSACTION;

INSERT INTO users(username, password, email) VALUES('charlie', 'hashed_pwd3', 'charlie@example.com');
SET @uid = LAST_INSERT_ID();
INSERT INTO user_role(user_id, role_id) VALUES(@uid, 2); -- 默认赋普通角色

COMMIT;

5.2 授权失败时回滚

START TRANSACTION;

-- 假设某权限不存在导致失败
INSERT INTO role_permission(role_id, permission_id) VALUES(1, 999);

-- 失败时回滚
ROLLBACK;

六、索引优化与执行分析

6.1 建议加索引字段

  • users.username:用于登录验证、搜索
  • login_logs.user_id:日志查询
  • user_role.user_id / role_permission.role_id:JOIN 优化
CREATE INDEX idx_username ON users(username);
CREATE INDEX idx_user_log ON login_logs(user_id);

6.2 执行计划分析

EXPLAIN SELECT u.username, r.name FROM users u JOIN user_role ur ON u.id = ur.user_id JOIN roles r ON ur.role_id = r.id;

可查看索引是否使用、JOIN 类型、Rows 扫描数量等。


更多推荐【MySQL完整系列】:MySQL数据库从0到拿捏系列

  1. MySQL数据库零基础入门教程:从安装配置到数据查询全掌握
    关键词:安装、登录、客户端、库表基础、简单查询

  2. MySQL数据表操作全指南:建表、修改、删除一步到位
    关键词:DDL语句、字段类型、主键/外键、约束、规范设计
    聚焦表结构的创建和维护,配合真实业务建表案例(如用户表、订单表)。

  3. MySQL增删改查基础教程:熟练掌握DML语句操作
    关键词:INSERT、UPDATE、DELETE、SELECT、WHERE、ORDER BY
    实战演练日常的数据库操作命令,重点讲解查询语句的条件与排序。

  4. MySQL高级查询技巧:分组、聚合、子查询与分页
    关键词:GROUP BY、HAVING、聚合函数、LIMIT、子查询
    向中级进阶,涵盖常见报表需求与分页列表的查询实现。

  5. MySQL多表查询详解:内连接、外连接、自连接通通搞懂
    关键词:JOIN、INNER JOIN、LEFT JOIN、UNION、自连接
    深度讲解表与表之间如何通过字段建立关联并进行数据整合。

  6. MySQL索引与性能优化入门:让查询提速的秘密武器
    关键词:索引原理、EXPLAIN、慢查询、查询优化
    开启性能优化之路,适合准备应对数据量增长或面试的人。

  7. MySQL事务与锁机制详解:确保数据一致性的关键
    关键词:事务四大特性、锁类型、死锁案例、隔离级别
    涉及电商、支付系统等对数据一致性要求高的业务场景。

  8. MySQL项目实战演练:搭建用户管理系统的完整数据库结构
    关键词:业务建模、表关系设计、数据初始化、查询场景
    以实战带动知识回顾,模拟真实业务项目,整合前面所学内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程间通信IV System V 系列(linux)

目录 消息队列 原理 操作 补充概念 信号量 (原子性计数器) 原理 操作 (和共享内存相似) 总结 小知识 消息队列 原理 在内核中建立一个队列&#xff0c;进程可以相互进行通信&#xff0c;通过队列进行IPC&#xff0c;就是进程之间发送带类型的数据块。 操作 接口和共享…

设计模式——建造者设计模式(创建型)

摘要 本文详细介绍了建造者设计模式&#xff0c;这是一种创建型设计模式&#xff0c;旨在将复杂对象的构建过程与其表示分离&#xff0c;便于创建不同表示。文中阐述了其设计意图&#xff0c;如隐藏创建细节、提升代码可读性和可维护性&#xff0c;并通过构建电脑的示例加以说…

使用Yolov8 训练交通标志数据集:TT100K数据集划分

使用Yolov8 训练交通标志数据集&#xff1a;TT100K数据集划分&#xff08;一&#xff09; 一、数据集下载二、划分数据集三、目录放置 一、数据集下载 官方网址&#xff1a;TT100K 数据集对比 源码如下&#xff1a; def classes(filedir):with open(filedir) as f:classes …

NLP学习路线图(十三):正则表达式

在自然语言处理&#xff08;NLP&#xff09;的浩瀚宇宙中&#xff0c;原始文本数据如同未经雕琢的璞玉。而文本预处理&#xff0c;尤其是其中至关重要的正则表达式技术&#xff0c;正是将这块璞玉转化为精美玉器的核心工具集。本文将深入探讨正则表达式在NLP文本预处理中的原理…

javaweb-maven以及http协议

1.maven坐标&#xff1a; 坐标是资源的唯一标识&#xff0c;通过该坐标可以唯一定位资源位置&#xff1b; 2.坐标的组成&#xff1a; groupId:定义当前项目隶书的组织名称&#xff1b; artifactId&#xff1a;定义当前maven项目名称 version&#xff1a;定义项目版本 3.依…

华为OD机试真题—— 最少数量线段覆盖/多线段数据压缩(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《最少数量线段覆盖/多线段数…

C语言创意编程:用趣味实例玩转基础语法(2)

文章目录 0. 前言1. &#x1f4ca; 动态条形图1.1 程序效果展示1.2 完整代码解析1.3 关键技术详解1.3.1 Unicode字符应用1.3.2 函数封装思想1.3.3 输入处理1.3.4 跨平台考虑 2. &#x1f524; 字母金字塔2.1 程序效果展示2.2 完整代码解析2.3 关键技术详解2.3.1 嵌套循环结构2.…

OpenCV CUDA模块图像处理------颜色空间处理之GPU 上对两张带有 Alpha 通道的图像进行合成操作函数alphaComp()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于在 GPU 上对两张带有 Alpha 通道的图像进行合成操作。支持多种常见的 Alpha 合成模式&#xff08;Porter-Duff 合成规则&#xff09;&…

OpenWebUI(1)源码学习构建

1. 前言 通过docker镜像拉取安装就不介绍了&#xff0c;官方的命令很多。本节主要撸一撸源码&#xff0c;所以&#xff0c;本地构建 2. 技术框架和启动环境 后端python&#xff0c;前端svelte 环境要求&#xff1a;python > 3.11 &#xff0c;Node.js > 20.10 3. 源…

npm error Cannot find module ‘negotiator‘ 的处理

本想运行npm create vuelatest&#xff0c;但提示&#xff1a; npm error code MODULE_NOT_FOUND npm error Cannot find module negotiator npm error Require stack: npm error - C:\Users\Administrator\AppData\Roaming\nvm\v18.16.1\node_modules\npm\node_modules\tuf-j…

爬虫入门指南-某专利网站的专利数据查询并存储

免责声明 本教程仅用于教育目的&#xff0c;演示如何合法获取公开专利数据。在实际操作前&#xff0c;请务必&#xff1a; 1. 仔细阅读目标网站的robots.txt文件和服务条款 2. 控制请求频率&#xff0c;避免对服务器造成负担 3. 仅获取和使用公开数据 4. 不用于商业用途或…

SQL(Database Modifications)

目录 Insertion Specifying Attributes in INSERT Adding Default Values&#xff08;缺省值&#xff09; Inserting Many Tuples Creating a Table Using the SELECT INTO Statement Deletion Example: Deletion Semantics of Deletion Updates Example: Update Sev…

【android bluetooth 案例分析 04】【Carplay 详解 2】【Carplay 连接之手机主动连车机】

1. 背景 在【android bluetooth 案例分析 04】【Carplay 详解 1】【CarPlay 在车机侧的蓝牙通信原理与角色划分详解】中我们从整理上介绍了车机中 carplay 相关基础概念。 本节 将详细分析 iphone手机主动 连接 车机carplay 这一过程。 先回顾一下 上一节&#xff0c; carpla…

【仿muduo库实现并发服务器】实现时间轮定时器

实现时间轮定时器 1.时间轮定时器原理2.项目中实现目的3.实现功能3.1构造定时任务类3.2构造时间轮定时器每秒钟往后移动添加定时任务刷新定时任务取消定时任务 4.完整代码 1.时间轮定时器原理 时间轮定时器的原理类似于时钟&#xff0c;比如现在12点&#xff0c;定一个3点的闹…

day15 leetcode-hot100-28(链表7)

2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 1.模拟 思路 最核心的一点就是将两个链表模拟为等长&#xff0c;不足的假设为0&#xff1b; &#xff08;1&#xff09;设置一个新链表newl来代表相加结果。 &#xff08;2&#xff09;链表1与链表2相加&#xff0c;具…

​​知识图谱:重构认知的智能革命​

在数字经济的浪潮中&#xff0c;知识图谱正悄然掀起一场认知革命。它不仅是技术的迭代&#xff0c;更是人类从“数据依赖”迈向“知识驱动”的里程碑。当谷歌用知识图谱优化搜索引擎、银行用它穿透复杂的金融欺诈网络、医院用它辅助癌症诊疗时&#xff0c;这项技术已悄然渗透到…

【计算机网络】4网络层①

这篇笔记讲IPv4和IPv6。 为了解决“IP地址耗尽”问题,有三种措施: ①CIDR(延长IPv4使用寿命) ②NAT(延长IPv4使用寿命) ③IPv6(从根本上解决IP地址耗尽问题) IPv6 在考研中考查频率较低,但需掌握基础概念以防冷门考点,重点结合数据报格式和与 IPv4 的对比记忆。…

MATLAB中的table数据类型:高效数据管理的利器

MATLAB中的table数据类型&#xff1a;高效数据管理的利器 什么是table数据类型&#xff1f; MATLAB中的table是一种用于存储列向数据的数据类型&#xff0c;它将不同类型的数据组织在一个表格结构中&#xff0c;类似于电子表格或数据库表。自R2013b版本引入以来&#xff0c;t…

Dropout 在大语言模型中的应用:以 GPT 和 BERT 为例

引言 大型语言模型&#xff08;LLMs&#xff09;如 GPT&#xff08;生成式预训练 Transformer&#xff09;和 BERT&#xff08;双向编码器表示 Transformer&#xff09;通过其强大的语言理解和生成能力&#xff0c;彻底改变了自然语言处理&#xff08;NLP&#xff09;领域。然…

gitLab 切换中文模式

点击【头像】--选择settings 选择【language】,选择中文&#xff0c;点击【保存】即可。