My SQL 索引

核心目标: 理解 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.mzph.cn/diannao/79819.shtml

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

相关文章

极狐GitLab 注册限制如何设置?

极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 注册限制 (BASIC SELF) 您可以对注册实施以下限制: 禁用新注册。新注册需要管理员批准。需要用户电子邮件确认。…

10.(vue3.x+vite)div实现tooltip功能(css实现)

1:效果截图 2:代码实现 <template><div><div class="tooltip" style="margin-top: 20%; margin-left: 20%; background-color: blueviolet; color: white;

Linux下 文件的查找、复制、移动和解压缩

1、在/var/log目录下创建一个hehe.log的文件&#xff0c;其文件内容是&#xff1a; myhostname ghl mydomain localdomain relayhost [smtp.qq.com]:587 smtp_use_tls yes smtp_sasl_auth_enable yes smtp_sasl_security_options noanonymous smtp_sasl_tls_security_opt…

Ubuntu 安装 Docker 教程(官方推荐方式)

✅ 步骤 1&#xff1a;卸载旧版本&#xff08;如果有&#xff09; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done---### ✅ 步骤 2&#xff1a;更新 APT 索引并安装依赖项bash sudo a…

计算机视觉与深度学习 | Transformer原理,公式,代码,应用

Transformer 详解 Transformer 是 Google 在 2017 年提出的基于自注意力机制的深度学习模型,彻底改变了序列建模的范式,解决了 RNN 和 LSTM 在长距离依赖和并行计算上的局限性。以下是其原理、公式、代码和应用的详细解析。 一、原理 核心架构 Transformer 由 编码器(Encod…

计算机基础 | 常见进制与单位简介 / 表示 / 描述

注&#xff1a;本文为 “进制与常见单位应用” 相关文章合辑。 原文为繁体&#xff0c;注意术语描述差异。 略作重排。 进制简介&#xff08;二进制、八进制、十进制、十六进制&#xff09; 发表于 2017-01-20 郑中胜 数字系统&#xff08;Numeral system&#xff09;&#…

门面模式与适配器模式

一、门面模式 门面模式&#xff1a;提供统一接口访问子系统接口 1、包含角色 外观系统对外的统一接口子系统类的集合&#xff1b;并不知道外观角色的存在&#xff0c;需要为了配合外观角色而做特殊处理或修改 2、举例 原本开关灯要分别操作各个房间的灯&#xff0c;现在设置总…

SpringBoot Actuator指标收集:Micrometer与Prometheus集成

文章目录 引言一、Spring Boot Actuator基础二、Micrometer简介与集成三、基本指标收集与配置四、自定义业务指标实现五、与Prometheus集成六、实战案例&#xff1a;API性能监控总结 引言 在现代微服务架构中&#xff0c;监控应用程序的健康状况和性能指标变得至关重要。Sprin…

【Android面试八股文】Android应用进程的启动流程【二】

应用进程 1.1 Android系统进程的启动过程&#xff1a; 1、init进程fork出Zygote进程后&#xff0c;Zygote进程会创建一个服务端socket&#xff0c;等待AMS发起socket请求。 同时&#xff0c;由Zygote进程fork出的SystemServer进程会启动各项系统服务&#xff0c;其中就包含了A…

基于Django的AI客服租车分析系统

基于Django的AI客服租车分析系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】AI智能客服与用户交互指导手册 【技术栈】 ①&#xff1a;系统环境&#xff1a;Python 3.8&#xff0c;Django 4.2框架 ②&#xff1a;开发环境&a…

全同态加密医疗数据分析集python实现

目录 摘要一、前言二、全同态加密与医疗数据分析概述2.1 全同态加密(FHE)简介2.2 医疗数据分析需求三、数据生成与预处理四、系统架构与流程4.1 系统架构图五、核心数学公式六、异步任务调度与(可选)GPU 加速七、PyQt6 GUI 设计八、完整代码实现九、自查测试与总结十、展望…

linux 搭建 dvwa 渗透测试环境

linux 安装 dvwa 1、分为4个部分&#xff0c;搭建dvwa渗透测试环境2、安装centos 7.63、安装apache http server4、安装mysql5、安装php6、运行dvwa 1、分为4个部分&#xff0c;搭建dvwa渗透测试环境 本文基于centos 7.6 搭建 dvwa 渗透测试环境 安装一个linux系统安装apache…

stm32(gpio的四种输出)

其实GPIO这个片上外设的功能&#xff1a; 用于控制IO引脚。 CPU就如同大脑&#xff0c;而这些片上外设就如同四肢一样的关系 如图 —————————————————————————————— OK类比了以上 其实GPIO是有 八种工作模式的 这八种工作模式 因为GPIO是面向IO…

Flask(3): 在Linux系统上部署项目

1 前言 说实话&#xff0c;我并不想接触linux系统&#xff0c;要记住太多的命令。我更习惯windows系统&#xff0c;鼠标点点&#xff0c;只要记住少量的命令就可以了。 但是我选择了python&#xff0c;就注定无法逃避linux系统。虽然python也能在windows上很好的运行&#xff0…

WIN10重启开机不用登录,直接进入桌面

我们个人机不需要登录。 步骤1 置&#xff0c;帐户&#xff0c;登录选项&#xff0c;密码。 输入当前密码后&#xff0c;直接下一步。 再次重启&#xff0c;就会发现不需要密码了。

idea中导入从GitHub上克隆下来的springboot项目解决找不到主类的问题

第一步&#xff1a;删除目录下的.idea和target&#xff0c;然后用idea打开 第二步&#xff1a;如果有需要&#xff0c;idea更换jdk版本 原文链接&#xff1a;https://blog.csdn.net/m0_74036731/article/details/146779040 解决方法&#xff08;idea中解决&#xff09;&#…

数字友好战略视域下数字安全核心要素的理论解构与实践路径

本论文聚焦数字友好战略框架下的数字安全核心要素&#xff0c;系统阐述数字安全的理论内涵、战略价值与实践路径。通过多维度分析数字安全在个人、企业与国家层面的作用机制&#xff0c;结合国际法规标准与前沿技术实践&#xff0c;揭示数字安全对构建可持续数字生态的关键支撑…

管理与维护samba服务器

允许 Linux、Unix 系统与 Windows 系统之间进行文件和打印机共享&#xff0c;使得不同操作系统的用户能够方便地访问和共享资源&#xff0c;就像在同一局域网中的 Windows 计算机之间共享资源一样。 server01安装Samba服务器 [rootserver ~]# rpm -qa | grep samba [rootserver…

前端面试每日三题 - Day 8

这是我为准备前端/全栈开发工程师面试整理的第八天每日三题练习&#xff0c;涵盖 JavaScript 闭包与执行上下文、React 性能优化与虚拟 DOM、以及高可用消息队列架构设计。 ✅ 题目 1&#xff1a;深入理解 JavaScript 中的闭包与执行上下文 &#x1f4d8; 解析&#xff1a; 闭…

996引擎-拓展变量:物品变量

996引擎-拓展变量:物品变量 测试代码参考资料对于Lua来说,只有能保存数据库的变量才有意义。 至于临时变量,不像TXT那么束手束脚,通常使用Lua变量就能完成。 测试代码 -- 存:物品拓展strfunction (player)local where =