My SQL 索引

news2025/4/23 10:29:58

核心目标: 理解 mysql 索引的工作原理、类型、优缺点,并掌握创建、管理和优化索引的方法,以显著提升数据库查询性能。

什么是索引?
索引是一种特殊的数据库结构,它包含表中一列或多列的值以及指向这些值所在物理行的指针(或对于聚集索引,直接包含数据)。其主要目的是加快数据检索(select 查询)的速度。你可以把它想象成一本书的目录或索引,让你能够快速定位到需要查找的内容,而不是逐页翻阅。

索引如何工作(简化理解)?
mysql 最常用的索引类型是 b-tree 索引(或其变种如 b+tree)。b-tree 是一种自平衡的树状数据结构,它保持数据有序,并允许高效地进行查找、插入、删除和顺序访问。当你在索引列上执行查询时(例如 where indexed_col = valueorder by indexed_col),数据库可以利用 b-tree 结构快速定位到匹配的行,避免了全表扫描(逐行检查)。

使用索引的优点

  1. 大幅提高查询速度: 这是索引最主要的好处,尤其是在 where 子句、join 操作的 on 子句中使用的列。
  2. 加速排序: 如果 order by 子句中的列有索引,mysql 可以直接利用索引的有序性返回结果,避免额外的排序操作。
  3. 加速分组: group by 操作通常也需要排序,索引可以帮助加速。
  4. 保证数据唯一性: unique 索引和 primary key 约束可以确保列值的唯一性。

使用索引的缺点 (cons)

  1. 占用存储空间: 索引本身也需要存储在磁盘上(或内存中),会增加数据库的总体积。
  2. 降低写入性能: 当对表进行 insert, update, delete 操作时,不仅要修改数据行,还需要同步更新相关的索引结构,这会增加写操作的开销。索引越多,写操作越慢。
  3. 索引维护成本: 索引需要维护,例如在数据大量变动后可能需要重建或优化(虽然 innodb 在这方面自动化程度较高)。

索引的类型

  • 按功能/逻辑分类:
1. 主键索引
  • 一种特殊的唯一索引,用于唯一标识表中的每一行。
  • 列值必须唯一 (unique) 且不能为空 (not null)。
  • 一个表只能有一个主键。
  • 通常在创建表时定义。innodb 表是围绕主键组织的(聚集索引)。
-- 建表时定义
create table users (
user_id int primary key,
username varchar(50) not null
);
-- 或表级定义 (用于单列或复合主键)
create table user_roles (
user_id int,
role_id int,
primary key (user_id, role_id)
);
2. 唯一索引
  • 确保索引列(或列组合)中的所有值都是唯一的。
  • 与主键不同,它允许一个 null
  • 主要目的是保证数据完整性,同时也能加速查询。
-- 建表时定义 (列级)
create table employees (
emp_id int primary key,
email varchar(100) unique
);
-- 建表时定义 (表级)
create table products (
product_id int primary key,
sku varchar(50),
constraint uq_sku unique (sku)
);
-- 后续添加
alter table employees add constraint uq_emp_ssn unique (social_security_number);
-- 或使用 create unique index
create unique index idx_uq_phone on customers (phone_number);
3. 普通索引 / 常规索引
  • 最基本的索引类型,没有唯一性限制。
  • 其唯一目的就是加速数据检索
  • keyindex 的同义词。
-- 建表时定义
create table logs (
log_id int primary key,
log_time datetime,
user_id int,
index idx_log_time (log_time), -- 创建普通索引
key idx_user_id (user_id) -- key 与 index 等效
);
-- 后续添加
alter table logs add index idx_message_prefix (log_message(50)); -- 前缀索引
-- 或使用 create index
create index idx_order_date on orders (order_date);
4. 复合索引 / 组合索引 / 多列索引
  • 在表的多个列上创建的索引。
  • 顺序非常重要! 遵循最左前缀原则 (leftmost prefix principle)
-- 建表时定义
create table orders (
order_id int primary key,
customer_id int,
order_date date,
index idx_cust_date (customer_id, order_date) -- 复合索引
);
-- 后续添加
alter table products add index idx_category_price (category_id, price);
5. 全文索引
  • 专门用于在文本列 (char, varchar, text) 中进行关键字搜索
  • 使用 match(column) against('keywords') 语法进行查询。
  • innodb (mysql 5.6+) 和 myisam 引擎支持。
-- 建表时定义
create table articles (
article_id int primary key,
title varchar(200),
body text,
fulltext index idx_ft_title_body (title, body)
) engine=innodb; -- 确保引擎支持
-- 后续添加
alter table articles add fulltext index idx_ft_body (body);
-- 查询
select * from articles where match(title, body) against('database performance');
6. (了解) 空间索引
  • 用于地理空间数据类型。优化地理位置查询。
-- create table spatial_table (
-- g geometry not null,
-- spatial index(g)
-- );
  • 按物理存储方式/结构分类 (主要是 innodb vs myisam):
    1. 聚集索引 (clustered index)

      • innodb 表强制要求有且只有一个。
      • 表的物理存储顺序与索引顺序一致,通常是按主键组织。
      • 优点:主键查找和范围查询快。缺点:插入慢,二级索引查找需两次。
    2. 非聚集索引 (non-clustered index) / 二级索引 (secondary index)

      • myisam 表的所有索引都是非聚集的。innodb 表的非主键索引是二级索引。
      • 索引逻辑顺序与数据物理存储顺序无关
      • 索引项包含索引值和指向数据行的指针(myisam)或主键值(innodb)。
      • 优点:插入快。缺点:查找可能需要额外步骤获取数据。

关键索引概念

  • 覆盖索引 (covering index)
    当查询所需的所有列都包含在使用的索引中时,mysql 直接从索引获取数据,无需访问数据行(回表),性能极高。
-- 对于 index idx_name_age (name, age)
-- 这个查询可以使用覆盖索引
select name, age from users where name = 'alice';
  • 索引选择性 (index selectivity)
    索引列中不同值的比例 (cardinality / total rows)。选择性越高(越接近 1),索引效果越好。性别列选择性低,身份证号列选择性高。

  • 前缀索引 (prefix indexing)
    对长字符串列只索引前缀部分,节省空间,提高速度。语法:index(column_name(prefix_length))。缺点:不能用于 order by/group by

alter table user_profiles add index idx_bio_prefix (biography(100));
  • 索引基数 (index cardinality)
    索引中唯一值的估计数量。show index 可查看。基数越高通常选择性越好。

  • (了解) 降序索引 (descending indexes)
    mysql 8.0+ 支持真正的 desc 索引,优化 order by ... desc

-- mysql 8.0+
create index idx_created_desc on articles (created_at desc);
  • (了解) 不可见索引 (invisible indexes)
    mysql 8.0+ 引入。优化器不使用,但索引仍维护。用于测试移除索引的影响。
alter table my_table alter index idx_name invisible; -- 设为不可见
alter table my_table alter index idx_name visible; -- 设为可见

索引管理语法

创建索引
  • 建表时 (create table): (见上文类型定义)
  • 使用 create index:
create index idx_name on table_name (column1, column2(10));
create unique index uq_email on users (email);
create fulltext index ft_content on documents (content);

使用 alter table:

alter table table_name add index idx_name (column_name);
alter table table_name add unique key uq_name (column_name);
alter table table_name add primary key (column_name); -- (如果尚无主键)
alter table table_name add fulltext index ft_name (column_name);
查看索引
  • show index from table_name;: 最常用,显示详细信息。
show index from employees;
  • show create table table_name;: 显示建表语句,包含索引定义。
show create table orders;
  • 查询 information_schema:
select index_name, column_name, index_type
from information_schema.statistics
where table_schema = 'your_database_name' and table_name = 'your_table_name';
删除索引
  • drop index index_name on table_name;: 最常用。
drop index idx_order_date on orders;
drop index uq_sku on products;
  • alter table table_name drop index index_name;: 功能同上。
alter table logs drop index idx_user_id;
  • alter table table_name drop primary key;: 删除主键。
alter table some_table drop primary key;
  • alter table table_name drop foreign key fk_name;: 删除外键约束。

选择哪些列加索引?

  1. where 子句频繁使用的列。
  2. join on 子句的连接列。
  3. order by 子句的列。
  4. group by 子句的列。
  5. 选择性高的列。
  6. 考虑复合索引(注意最左前缀和列顺序)。

索引失效(不被使用)的常见情况

  1. 对索引列使用函数或表达式 (where year(col)=...)。
  2. like 查询以 % 开头 (where name like '%son')。
  3. or 条件两边未都建立合适索引。
  4. 数据类型不匹配 / 隐式类型转换 (where string_col = 123)。
  5. 索引选择性过低。
  6. 表数据量过小。
  7. mysql 优化器认为全表扫描更快。

索引优化与 explain

  • explain 命令: 分析 select 执行计划的关键工具。查看 type, key, rows 等字段判断索引使用情况。
explain select * from users where username = 'test';
  • 定期维护 (相对次要,尤其对 innodb):
    • analyze table table_name;: 更新统计信息。
    • optimize table table_name;: myisam 整理碎片;innodb 通常重建表。

总结与最佳实践

  • 索引提速查询,但降低写入性能、占空间。
  • 理解 innodb (默认) 和 myisam 区别。
  • 优先索引 where, join, order by, group by 的列。
  • 善用复合索引(最左前缀)和覆盖索引。
  • 避免索引列上用函数、隐式转换、like '%...'
  • explain 分析和验证索引效果。
  • 不过度索引,定期审查。

练习题

假设有 orders 表: (order_id int pk, customer_id int, product_name varchar(100), quantity int, order_date date)

  1. orders 表的 customer_id 列添加一个普通索引,名为 idx_cust_id
    答案:
alter table orders add index idx_cust_id (customer_id);
-- 或者
-- create index idx_cust_id on orders (customer_id);
  1. orders 表添加一个复合索引,包含 order_dateproduct_name (前 50 个字符),索引名为 idx_date_product
    答案:
alter table orders add index idx_date_product (order_date, product_name(50));
  1. 假设需要确保每个客户在同一天的同一个产品只能下一个订单。请为 orders 表添加一个合适的唯一约束(假设可以基于 customer_id, order_date, product_name)。约束名为 uq_cust_date_prod
    答案:
alter table orders add constraint uq_cust_date_prod unique (customer_id, order_date, product_name);
  1. 查看 orders 表上存在的所有索引。
    答案:
show index from orders;
  1. 删除第 2 题创建的复合索引 idx_date_product
    答案:
drop index idx_date_product on orders;
-- 或者
-- alter table orders drop index idx_date_product;
  1. 分析以下查询的执行计划(假设 customer_id 列已有索引 idx_cust_id):explain select order_id, product_name from orders where customer_id = 123 order by order_date; 思考 order by 是否能利用索引。
    答案:
explain select order_id, product_name from orders where customer_id = 123 order by order_date;

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

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

相关文章

【DeepSeek 学习推理】Llumnix: Dynamic Scheduling for Large Language Model Serving实验部分

6.1 实验设置 测试平台。我们使用阿里云上的16-GPU集群(包含4个GPU虚拟机,类型为ecs.gn7i-c32g1.32xlarge)。每台虚拟机配备4个NVIDIA A10(24 GB)GPU(通过PCI-e 4.0连接)、128个vCPU、752 GB内…

Kubernetes相关的名词解释kubeadm(19)

kubeadm是什么? kubeadm 是 Kubernetes 官方提供的一个用于快速部署和管理 Kubernetes 集群的命令行工具。它简化了集群的初始化、节点加入和升级过程,特别适合在生产环境或学习环境中快速搭建符合最佳实践的 Kubernetes 集群。 kubeadm 的定位 不是完整…

什么是负载均衡?NGINX是如何实现负载均衡的?

大家好,我是锋哥。今天分享关于【什么是负载均衡?NGINX是如何实现负载均衡的?】面试题。希望对大家有帮助; 什么是负载均衡?NGINX是如何实现负载均衡的? 1000道 互联网大厂Java工程师 精选面试题-Java资源…

基于Python(Django)+SQLite实现(Web)校园助手

校园助手 本校园助手采用 B/S 架构。并已将其部署到服务器上。在网址上输入 db.uplei.com 即可访问。 使用说明 可使用如下账号体验: 学生界面: 账号1:123 密码1:123 账户2:201805301348 密码2:1 # --------------…

从零开始搭建Django博客②--Django的服务器内容搭建

本文主要在Ubuntu环境上搭建,为便于研究理解,采用SSH连接在虚拟机里的ubuntu-24.04.2-desktop系统搭建,当涉及一些文件操作部分便于通过桌面化进行理解,通过Nginx代理绑定域名,对外发布。 此为从零开始搭建Django博客…

【读论文】HM-RAG:分层多智能体多模态检索增强生成

如何在多模态信息检索和生成中,通过协作式多智能体系统来处理复杂的多模态查询。传统的单代理RAG系统在处理需要跨异构数据生态系统进行协调推理的复杂查询时存在根本性限制:处理多种查询类型、数据格式异质性和检索任务目标的多样性;在视觉内容和文本内…

文件操作和IO(上)

绝对路径和相对路径 文件按照层级结构进行组织(类似于数据结构中的树型结构),将专门用来存放管理信息的特殊文件称为文件夹或目录。对于文件系统中文件的定位有两种方式,一种是绝对路径,另一种是相对路径。 绝对路径…

JavaFX深度实践:从零构建高级打地鼠游戏(含多物品与反馈机制)

大家好!经典的“打地鼠”游戏是许多人童年的回忆,也是学习 GUI 编程一个非常好的切入点。但仅仅是“地鼠出来就打”未免有些单调。今天,我们来点不一样的——用 JavaFX 打造一个高级版的打地鼠游戏!在这个版本中,洞里钻…

Python 简介与入门

目录 一、Python 初识 1、Python 的优势 2、Python 的特性 3、Python 的应用领域 二、Linux 环境中安装 Python 1、下载 Python3.11.6 2、安装依赖包 3、解压 Python 压缩包 4、安装 Python 5、编译及安装 6、建立软链接 7、测试 Python3 运行 8、设置国内 pip 更…

理解RAG第六部分:有效的检索优化

在RAG系统中,识别相关上下文的检索器组件的性能与语言模型在生成有效响应方面的性能同样重要,甚至更为重要。因此,一些改进RAG系统的努力将重点放在优化检索过程上。 从检索方面提高RAG系统性能的一些常见方法。通过实施高级检索技术&#x…

实训Day-2 流量分析与安全杂项

目录 实训Day-2-1流量分析实战 实训目的 实训任务1 SYN半链接攻击流量分析 实训任务2 SQL注入攻击流量分析一 实训任务3 SQL注入攻击流量分析二 实训任务4 Web入侵溯源一 实训任务5 Web入侵溯源二 ​编辑 实训Day-2-1安全杂项实战 实训目的 实训任务1 流量分析 FTP…

几种电气绝缘类型

1. 基本绝缘 1.1 绝缘等级 1.2 I类设备 2. 附加绝缘 3. 双重绝缘 4. 加强绝缘 5. 功能性绝缘 1. 基本绝缘 用于防止触及带电部件的初级保护,该防护是由绝缘材料完成的 基本绝缘的目的在于为防电击提供一个基本的保护,以避免触电的危险,不过此类绝缘只能保证正常状态下…

char32_t、char16_t、wchar_t 用于 c++ 语言里存储 unicode 编码的字符,给出它们的具体定义

&#xff08;1&#xff09; #include <iostream> #include <string>int main() { std::u16string s u"C11 引入 char16_t"; // 定义 UTF-16 字符串for (char16_t c : s) // 遍历输出每个 char16_t 的值std::cout << std::hex << (…

Java Set/List 知识点 Java面试 基础面试题

Java Set/List 知识点 Set与List区别 List 有序、值可重复,内部数据结构 Obejct[ ] 数组Set 无序、值不重复,内部数据结构 HashMap keyobject value固定new Object() ArrayList 有序存储元素允许元素重复&#xff0c;允许存储 null 值支持动态扩容非线程安全 HashSet、LinkedHa…

Oracle Database Resident Connection Pooling (DRCP) 白皮书阅读笔记

本文为“Extreme Oracle Database Connection Scalability with Database Resident Connection Pooling (DRCP)”的中文翻译加阅读笔记。觉得是重点的就用粗体表示了。 白皮书版本为March 2025, Version 3.3&#xff0c;副标题为&#xff1a;Optimizing Oracle Database resou…

FastAPI WebSocket 聊天应用详细教程

项目简介 这是一个基于 FastAPI 和 WebSocket 实现的实时聊天应用&#xff0c;支持一对一聊天、离线消息存储等功能。 技术栈 后端&#xff1a;FastAPI (Python)前端&#xff1a;HTML、JavaScript、CSS通信&#xff1a;WebSocket认证&#xff1a;简单的 token 认证 项目结构…

vue3+canvas裁剪框样式【前端】

目录 canvas绘制裁剪框&#xff1a;拖拽改变框的大小&#xff1a;圆圈样式&#xff1a;方块样式&#xff1a; canvas绘制裁剪框&#xff1a; // 绘制裁剪框 const drawCropRect (ctx: CanvasRenderingContext2D): void > {if (cropRect.value.width > 0 && crop…

软件功能测试和非功能测试有什么区别和联系?

软件测试是保障软件质量的核心环节&#xff0c;而软件功能测试和非功能测试作为测试领域的两大重要组成部分&#xff0c;承担着不同但又相互关联的职责。 软件功能测试指的是通过验证软件系统的各项功能是否按照需求规格说明书来正确实现&#xff0c;确保软件的功能和业务流程…

10_C++入门案例习题: 结构体案例

案例描述 学校正在做毕设项目&#xff0c;每名老师带领5个学生&#xff0c;总共有3名老师&#xff0c;需求如下 设计学生和老师的结构体&#xff0c;其中在老师的结构体中&#xff0c;有老师姓名和一个存放5名学生的数组作为成员 学生的成员有姓名、考试分数&#xff0c; 创建…

快速定位达梦缓存的执行计划并清理

开发告诉你一个sql慢&#xff0c;你想看看缓存中执行计划时&#xff0c;怎么精准快速定位&#xff1f; 可能一般人通过文本内容模糊搜索 select cache_item, substr(sqlstr,1,60)stmt from v$cachepln where sqlstr like %YOUR SQL STRING%; 搜出来的内容比较多&#xff0c;研…