当前位置: 首页 > news >正文

MySQL笔记---索引

1. 索引的概念

在 MySQL 中,索引是一种特殊的数据结构,它与数据表关联,能帮助数据库高效查询数据,避免全表扫描(遍历所有记录),显著提升查询性能

准确来说,索引是绑定到数据表的某一行或某几行的。

一个索引就是一个能通过键值快速查找目标的数据结构(例如红黑树、哈希表、B+树等),而为某一行建立索引,本质上就是以该行的值为键值建立一个用于查找的数据结构

这样,在以该行为筛选条件查询记录时,查询速度就会有明显的提升。

1.1 索引的作用

  • 加速查询:通过索引快速定位符合条件的记录(类似书籍的目录)。
  • 优化排序 / 分组:若查询包含 ORDER BY 或 GROUP BY,合适的索引可避免额外排序操作。
  • 约束作用:某些索引(如主键、唯一索引)可保证数据唯一性。

1.2 索引的类型

(1)按数据结构划分

  • B + 树索引(最常用): MySQL 大多数存储引擎(如 InnoDB、MyISAM)默认使用 B + 树作为索引结构。
    • 特点:有序性、平衡性,叶子节点存储数据(InnoDB 聚簇索引)或指针(MyISAM 非聚簇索引)。
    • 适用场景:范围查询(>、<、BETWEEN)、精确匹配(=)、排序(ORDER BY)等。
  • 哈希索引: 基于哈希表实现,适用于精确匹配(=),但不支持范围查询和排序。
    • InnoDB 中仅 “自适应哈希索引”(自动为热点数据创建,不可手动干预)。
  • 其他索引
    • 全文索引:用于文本内容的模糊查询(如 MATCH AGAINST),支持自然语言搜索。
    • R-tree 索引:用于空间数据类型(如 GEOMETRY),较少使用。

(2)按功能划分

  • 主键索引(PRIMARY KEY): 唯一标识一条记录,不允许 NULL,一张表只能有一个主键索引。 InnoDB 中,主键索引是聚簇索引(数据与索引存储在一起)。
  • 唯一索引(UNIQUE): 确保索引列的值唯一,但允许 NULL(多个 NULL 不冲突),一张表可有多列唯一索引。
  • 普通索引(INDEX): 无唯一性约束,仅用于加速查询,可创建在任意列。
  • 联合索引(复合索引)
    • 基于多列创建的索引(如 INDEX idx_name_age (name, age))。
    • 遵循 “最左前缀原则”:查询条件需包含索引的最左列才能触发索引(如 WHERE name='xxx' 可命中,WHERE age=18 不可)。

1.3 索引的使用场景

  • 适合创建索引的场景
    • 频繁用于 WHERE 条件、JOIN 关联、ORDER BY/GROUP BY 的列。
    • 基数高(取值范围大、重复值少)的列(如身份证号),基数低的列(如性别)不适合。
    • 字符串列可针对前缀创建索引(如 INDEX idx_title (title(10))),节省空间。
  • 不适合创建索引的场景
    • 表数据量小(全表扫描速度可能更快)。
    • 频繁更新的列(索引会增加更新成本)。
    • 很少查询的列。
    • 包含大量 NULL 的列(索引对 NULL 处理效率低)。

1.4 索引失效的常见情况

即使创建了索引,某些查询可能无法命中索引,导致全表扫描:

  • 索引列参与计算或函数操作(如 WHERE YEAR(create_time) = 2023)。
  • 使用 NOT、!=、<> 等否定操作符(可能失效,视情况而定)。
  • 字符串不加引号(如 WHERE name=123,实际类型为字符串时会隐式转换)。
  • 使用 OR 连接非索引列(如 WHERE idx_col=1 OR no_idx_col=2)。
  • 违背联合索引的 “最左前缀原则”。 LIKE 以通配符开头(如 WHERE name LIKE '%abc')。

1.5 索引的代价

  • 空间代价:索引会占用额外存储空间。
  • 时间代价:插入、更新、删除数据时,需同步维护索引结构,降低写操作效率。

因此,索引并非越多越好,需根据业务查询特点 “按需创建”

2. 索引的用法

2.1 查看索引

SHOW INDEX FROM table_name;mysql> SHOW INDEX FROM emp;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| emp   |          0 | PRIMARY     |            1 | empno       | A         |          15 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | fk_emp_mgr  |            1 | mgr         | A         |           8 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | fk_emp_dept |            1 | deptno      | A         |           5 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.02 sec)SHOW INDEX FROM table_name \G;mysql> SHOW INDEX FROM emp \G;
*************************** 1. row ***************************Table: emp         -- 表名称Non_unique: 0Key_name: PRIMARY     -- 键类型Seq_in_index: 1           -- 在复合索引中的位置Column_name: empno       -- 绑定到的列Collation: ACardinality: 15Sub_part: NULLPacked: NULLNull: Index_type: BTREE       -- 索引类型,这里的BTREE指B+树而非B树Comment: 
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: empNon_unique: 1Key_name: fk_emp_mgrSeq_in_index: 1Column_name: mgrCollation: ACardinality: 8Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment: 
Index_comment: Visible: YESExpression: NULL
*************************** 3. row ***************************Table: empNon_unique: 1Key_name: fk_emp_deptSeq_in_index: 1Column_name: deptnoCollation: ACardinality: 5Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment: 
Index_comment: Visible: YESExpression: NULL
3 rows in set (0.00 sec)

2.2 主键索引

作为主键的列自带主键索引,无需用户显示创建。

2.3 唯一索引

同样地,唯一键自带唯一索引。

关于键的操作,请参考:https://the-old.blog.csdn.net/article/details/152162625?spm=1011.2415.3001.5331

在确保某列无重复数据的情况下,也可手动添加唯一索引:

CREATE UNIQUE INDEX idx_name ON table_name (column_name);

2.4 普通索引

-- 创建表时定义索引
CREATE TABLE table_name (column_name 类型 [约束条件], INDEX idx_col (column_name)
);-- 添加普通索引
CREATE INDEX idx_name ON table_name (column_name);

2.5 联合索引

-- 创建表时定义索引
CREATE TABLE table_name (column_name1 类型 [约束条件],column_name2 类型 [约束条件], INDEX idx_name (column_name1, column_name2)
);-- 添加联合索引
CREATE INDEX idx_name ON table_name (column_name1, column_name2);

注意:只有在查询条件包含首列的情况下,联合索引才会被触发,这就是“最左前缀原则”。

原因我们会在下文介绍。

2.6 删除索引

DROP INDEX idx_name ON table_name;

3. 索引底层原理

MySQL 索引的底层原理核心围绕数据结构存储引擎的实现逻辑展开,其中最关键的是 B + 树(大多数存储引擎的默认选择)。

3.1 为什么选择 B + 树作为主流索引结构

索引的核心目标是减少磁盘 IO 次数(因为磁盘 IO 速度远慢于内存操作)。MySQL 中数据和索引都存储在磁盘上,索引需要通过高效的结构快速定位数据位置,减少磁盘访问次数。

磁盘读写数据的基本单位为一个扇区(512B),操作系统读写数据的基本单位为一个数据块(8个扇区,即4KB),而MySQL读写数据的基本单位为一个页面(Page,16KB)

经过前面的介绍,我们当然不会选择哈希表作为索引的主流选择。所以剩下来的选择就是“树”

而无论采用何种数据结构,我们都不能保证一次查询所涉及到的所有结点都在一个页面内。每次查询经过的结点越多,涉及到的页面也就越多,磁盘IO次数也就越多。

因此,我们需要的一定是一个矮胖的多叉树,这样才能减少结点的访问次数。

对比其他数据结构的缺陷:

  • 二叉树:可能退化为链表(如有序数据插入时),查询效率暴跌(O (n))。
  • 红黑树(平衡二叉树):树高随数据量增长较快(百万级数据树高约 20),磁盘 IO 次数多。
  • B 树:非叶子节点也存储数据,导致单次 IO 加载的节点数据量少,树高更高,范围查询效率低。

B + 树完美解决了这些问题,成为 MySQL(InnoDB、MyISAM 等)的首选:

  • 结构特点: 是一种多路平衡查找树,所有数据都存储在叶子节点,且叶子节点之间通过双向链表连接;非叶子节点仅存储索引键(作为 “目录”),不存实际数据。
  • 优势
    • 树高低:多路分支(如每个节点可存 1000 个索引键,3 层即可存 10 亿数据),减少磁盘 IO 次数(通常 3-4 次 IO 即可定位数据)。
    • 范围查询高效:叶子节点链表有序,范围查询(如BETWEEN、ORDER BY)可直接通过链表遍历,无需回溯上层节点。
    • IO 效率高:非叶子节点仅存索引键,单次磁盘 IO 可加载更多索引键,减少查询时的 IO 次数。

3.2 结点与页

B + 树的每个节点(包括根节点、非叶子节点、叶子节点)的大小会被设计为接近一个页的大小(16KB)。因此,每个节点会被完整地存储在一个单独的页中:

  • 非叶子节点:存储索引键和指向子节点的指针(每个指针指向另一个页,即子节点);
  • 叶子节点:存储索引键和数据(InnoDB 聚簇索引的叶子节点存完整数据行,二级索引存主键;MyISAM 存数据行物理地址)。

这种设计的核心目的是最大化单次磁盘 IO 的效率—— 一次 IO 就能加载整个节点的所有索引键和指针,避免因节点跨多个页导致的多次 IO。

实际中,节点可能不会完全填满页(例如新创建的索引、数据量较少时)。

但即便如此,节点仍会占用一个完整的页(剩余空间会空闲,或后续插入数据时填充)。

不会出现 “多个节点挤在一个页中” 的情况,因为这会导致读取一个节点时不得不加载其他无关节点的数据,浪费 IO 资源。

3.3 不同存储引擎的索引实现

MySQL 的索引实现与存储引擎强相关,最典型的是InnoDB和MyISAM。

3.3.1 InnoDB 的索引实现(聚簇索引 + 二级索引)

InnoDB 是 MySQL 默认存储引擎,其索引核心是聚簇索引(Clustered Index),即 “索引与数据存储在一起”

  • 聚簇索引(主键索引)
    • 必须基于主键创建(若未显式定义主键,InnoDB 会隐式选择唯一非空列作为主键;若没有,则生成隐藏的 6 字节row_id作为主键)。
    • 结构:B + 树的叶子节点直接存储完整的数据行(包括所有列的值)。
      例:若表user的主键为id,则聚簇索引的叶子节点存储(id, name, age, ...)完整行数据。
  • 二级索引(辅助索引 / 非主键索引): 基于非主键列创建的索引(如普通索引、唯一索引、联合索引等)。
    • 结构:B + 树的叶子节点不存储完整数据行,而是存储主键值(聚簇索引的键)
    • 查询过程:通过二级索引查询时,需先定位到叶子节点获取主键值,再通过聚簇索引查询完整数据行,这个过程称为 “回表”
      例:若user表有name列的二级索引,查询WHERE name='Bob'时,先通过name索引找到主键id=15,再用id=15查聚簇索引得到完整数据。
  • 联合索引的底层: 基于多列创建的 B + 树,索引键按列顺序排序(如(name, age)联合索引,叶子节点按name先排序,name相同则按age排序)。这也是 “最左前缀原则” 的底层原因:只有从最左列开始匹配,才能沿 B + 树的有序结构定位。
3.3.2 MyISAM 的索引实现(非聚簇索引)

MyISAM 的索引与数据完全分离,所有索引(包括主键索引)都是非聚簇索引。

  • 结构
    • 索引的 B + 树叶子节点存储的是数据行的物理地址(即数据在磁盘上的存储位置,类似文件指针)。
    • 数据单独存储在数据文件中,与索引文件分离。
  • 查询过程: 无论主键索引还是二级索引,找到叶子节点的物理地址后,直接通过地址访问数据文件获取完整行,无需回表(因为地址直接指向数据)。
  • 缺点: 由于索引与数据分离,范围查询效率低于 InnoDB(InnoDB 的叶子节点链表更高效);且不支持事务和行级锁,现在已较少使用。
http://www.dtcms.com/a/450192.html

相关文章:

  • 免费做自荐书的网站网站设计怎么算间距
  • 在线制作表白网站的源码雄安新区网站建设
  • 让“通感”更聪明:人工智能在通信感知一体化中的非线性建模优势
  • 2024年ASOC SCI2区TOP,费马-韦伯定位粒子群算法+无人机协同路径规划,深度解析+性能实测
  • 政务网站平台建设 招标河北省建设网站的网站首页
  • 怎样建设美食网站wordpress外网排版问题
  • 自助建站网站程序源码手机网站建设注册塔山双喜
  • 内卷式迷茫-当游戏沉迷与疯狂刷题成为“空心病”的双重面具-AI
  • dedecms 网站名称网站开发与建设方向
  • Oracle OCP认证考试题目详解082系列第56题
  • 织梦网站首页文字修改响应式网页制作
  • uv `pyvenv.cfg` is missing micromaba环境报错解决
  • 还原论与系统论在计算机科学中的应用
  • 做明星ps黄图网站陕西建设网网站集群
  • 制作公司网站用阿里云响应式网站 软件
  • 视频号下载器 (1)
  • 电源——BOOST电路设计实战
  • 专业app开发定制公司网络优化的内容包括哪些
  • 海南省两学一做网站flash同视频做网站
  • BLDCPMSM电机控制器硬件设计工程(六)大功率控制器功率模块驱动电源方案
  • 中秋赏月互动页面:用前端技术演绎传统节日之美
  • 网站建设swot网店装修是什么意思
  • 企业为什么要做网络营销推广西宁做网站seo
  • C语言易错点大总结
  • 建设电子商务网站的启示邮箱登录入口qq网页版
  • LeetCode:100.寻找重复数
  • 还原论与系统论在学习与认知中的启示
  • 【AI论文】Vision-Zero:通过策略性游戏化自对弈实现可扩展的视觉语言模型(VLM)自优化
  • 实验三:栈和队列
  • wordpress实现pdf浏览器舆情优化公司