Mysql中索引的知识

Mysql中的索引的定义和种类

核心概念:索引是什么?

想象一下你有一本很厚的书,你想找到其中关于某个特定主题的内容。你有两种方法:

  1. 从头到尾翻阅整本书 :这就像数据库中的全表扫描 (Full Table Scan)。如果书很长,这个过程会非常慢。

  2. 查阅书末尾的索引 :索引列出了书中的重要词汇或主题,并指明了它们出现在书的哪一页。你只需要快速查找索引(索引本身通常按字母排序),找到你想找的主题,然后直接翻到对应的页码。这就像数据库中的使用索引

在数据库中,索引也是一个类似的数据结构 ,它存储了表中的某个(或多个)列的值,并关联着这些值对应的行的物理位置或唯一标识。它的主要目的是 加快数据的检索速度

索引的本质:

  • 一个独立于表数据之外的数据结构

  • 存储了表中列的有序副本(或部分副本)。

  • 包含了指向原始数据行的指针或引用。

有了索引,数据库系统在执行查询时,就可以先在索引结构中快速定位到符合条件的索引项,然后通过索引项找到对应的数据行,而不需要扫描整个表的数据文件。

为什么索引的种类感觉很多?

索引的"种类"多,是因为我们从不同的维度去划分和命名索引:

  1. 根据数据结构: 索引底层使用什么数据结构来组织数据(最常见的是 B-Tree/B+Tree)。

  2. 根据逻辑功能或约束: 索引除了加速查询,是否还具备其他功能或强制约束(例如,是否要求索引列的值唯一)。

  3. 根据索引和数据行的关联方式: 索引的数据和实际的表数据是如何存放和关联的(主要是 InnoDB 引擎中的概念,聚簇索引 vs 非聚簇索引/二级索引)。

理解了这几个维度,就能明白为什么会有各种不同的索引名称。

常见索引种类(举例):

我们主要以最常用的 InnoDB 存储引擎 来讲解,因为它对索引的处理方式(特别是聚簇索引)非常有代表性。

1. 根据数据结构:

  • B-Tree (B+Tree) 索引:

    • 这是 MySQL 中最常见的索引类型,特别是 InnoDB 引擎的标准索引。

    • 结构:一种平衡的多路搜索树。

      • 节点(非叶子节点)存储索引键的范围和指向子节点的指针。

      • 叶子节点存储完整的索引键,并包含指向实际数据行(对于二级索引)或直接包含数据行本身(对于聚簇索引)的指针。

      • B+Tree 特点: 所有的真实数据或指向数据的指针都只存在于叶子节点,并且叶子节点之间通过双向链表连接。这使得范围查询非常高效。

    • 适用场景:等值查找、范围查找、排序(前缀匹配)。

    • 例子: 你创建的大部分 PRIMARY KEY, UNIQUE, INDEX (普通索引) 默认都是 B+Tree 索引。

  • Hash 索引:

    • 基于哈希表实现。

    • 结构:将索引列的值进行哈希计算,得到一个哈希值,然后将这个哈希值映射到存储数据行指针的地址。

    • 适用场景:只适用于等值查找 (=)。无法用于范围查找、排序或模糊匹配(如 LIKE 'prefix%')。

    • 特点:查找速度理论上非常快 (O(1) 平均)。但在 MySQL 中,只有 MEMORY 存储引擎默认支持 Hash 索引,InnoDB 引擎虽然也支持一种称为 "Adaptive Hash Index" 的特性,但它是 InnoDB 内部根据工作负载自动创建和管理的,你无法手动创建 Hash 索引。

    • 例子: MEMORY 表的 PRIMARY KEY 或 UNIQUE INDEX 默认使用 Hash 索引。你不能用 CREATE INDEX ... USING HASH 来创建 InnoDB 表的 Hash 索引。

  • Fulltext 索引 (全文索引):

    • 用于在大文本字段 (如 TEXT, VARCHAR) 中进行关键词搜索。

    • 结构:通常使用倒排索引 (Inverted Index)。记录了哪些词出现在了哪些文档(行)中。

    • 适用场景:搜索文章、博客内容等包含大量文本的字段。

    • 使用方式:使用 MATCH(column_name) AGAINST('keywords') 语法进行查询。

    • 例子: 在存储文章内容的 TEXT 字段上创建 FULLTEXT INDEX。

      复制代码
      ALTER TABLE articles ADD FULLTEXT INDEX idx_content (content);
      SELECT title FROM articles WHERE MATCH(content) AGAINST('MySQL Index');
  • Spatial 索引 (空间索引):

    • 用于存储和检索地理空间数据 (如点、线、多边形)。

    • 结构:通常使用 R-Tree

    • 适用场景:地理信息系统 (GIS) 应用,查找某个区域内的点,判断图形是否相交等。

    • 使用方式:需要使用 MySQL 的空间数据类型 (GEOMETRY, POINT, POLYGON 等) 和空间函数。

    • 例子: 在存储坐标的 POINT 字段上创建 SPATIAL INDEX。

      复制代码
      CREATE TABLE cities (
          name VARCHAR(255),
          location POINT,
          SPATIAL INDEX idx_location (location)
      );
      -- 查询某个矩形区域内的城市
      SELECT name FROM cities WHERE MBRContains(GeomFromText('POLYGON((...))'), location);

2. 根据逻辑功能或约束:

  • Primary Key (主键索引):

    • 功能/约束:唯一标识表中的每一行。值必须是唯一的,并且不能为 NULL。

    • 特殊性 (InnoDB):它不仅仅是一个索引,它也是 聚簇索引 (后面会解释)。

    • 一个表最多只能有一个主键。

    • 例子:

      复制代码
      CREATE TABLE users (
          user_id INT PRIMARY KEY, -- 创建主键索引
          username VARCHAR(50) UNIQUE,
          ...
      );
  • Unique Index (唯一索引):

    • 功能/约束:确保索引列中的所有值都是唯一的。允许包含 NULL 值(如果列定义允许 NULL 的话,多个 NULL 值是允许的,因为 NULL 不等于 NULL)。

    • 一个表可以有多个唯一索引。

    • 例子: 确保用户名或邮箱地址是唯一的。

      复制代码
      ALTER TABLE users ADD UNIQUE INDEX idx_username (username); -- 创建唯一索引
      ALTER TABLE users ADD UNIQUE INDEX idx_email (email);     -- 创建另一个唯一索引
  • Standard Index / Non-Unique Index (普通索引 / 非唯一索引):

    • 功能/约束:没有任何约束,唯一的作用就是提高查询性能。

    • 索引列的值可以重复。

    • 一个表可以有多个普通索引。

    • 例子: 提高按加入日期查询或排序的速度。

      复制代码
      CREATE INDEX idx_join_date ON users (join_date); -- 创建普通索引
  • Composite Index (复合索引 / 组合索引):

    • 功能/约束:在多个列上创建一个索引。

    • 查询时只有使用了索引的前缀(从左到右的列)才能有效地利用该索引。例如,在 (col1, col2, col3) 上创建的复合索引,可以用于查询 WHERE col1 = ...、WHERE col1 = ... AND col2 = ...、WHERE col1 = ... AND col2 = ... AND col3 = ...,但不能直接用于 WHERE col2 = ... 或 WHERE col3 = ...。

    • 例子: 提高按用户名和邮箱联合查询的速度。

      复制代码
      CREATE INDEX idx_username_email ON users (username, email); -- 创建复合索引

3. 根据索引和数据行的关联方式 (主要在 InnoDB 中):

这是理解 InnoDB 索引的关键。

  • Clustered Index (聚簇索引):

    • 特点: 索引的叶子节点直接存储了表的所有行数据

    • 数据行是根据聚簇索引键的顺序物理地存储在磁盘上的。

    • 一个表只能有一个聚簇索引。

    • 在 InnoDB 中,聚簇索引通常是:

      • 如果你定义了 PRIMARY KEY,那么它就是聚簇索引。

      • 如果你没有定义 PRIMARY KEY,但定义了 UNIQUE NOT NULL 索引,那么第一个这样的索引会被选为聚簇索引。

      • 如果上述两者都没有,InnoDB 会隐式地创建一个隐藏的聚簇索引(一个 6 字节的 ROW_ID)。

    • 查询速度非常快,特别是按主键等值查询或范围查询,因为索引结构直接指向了完整的数据行。

    • 插入数据时,需要根据主键顺序找到合适的物理位置进行插入,可能会导致页分裂。

  • Secondary Index (二级索引 / 非聚簇索引):

    • 特点: 索引的叶子节点存储了索引键的值,以及指向对应聚簇索引键值的指针。

    • 它不包含完整的数据行。

    • 一个表可以有多个二级索引。

    • 查询流程:先通过二级索引找到对应的聚簇索引键值,然后再通过聚簇索引键值去聚簇索引中查找完整的数据行 。这个过程称为回表 (Lookup)

    • 例子: 除了主键之外你创建的所有 UNIQUE, INDEX, FULLTEXT, SPATIAL 索引都是二级索引。

理解例子:

假设我们有 users 表:

复制代码
CREATE TABLE users (
    user_id INT PRIMARY KEY,          -- 主键,同时是聚簇索引
    username VARCHAR(50) UNIQUE,      -- 唯一索引,二级索引
    email VARCHAR(100),               -- 普通字段
    join_date DATE,                   -- 普通字段
    status ENUM('active', 'inactive'), -- 普通字段
    INDEX idx_join_date (join_date)   -- 普通索引,二级索引
) ENGINE=InnoDB;
  • 当你执行 SELECT * FROM users WHERE user_id = 100; 时,MySQL 使用聚簇索引,直接根据 user_id = 100 在聚簇索引 B+Tree 中找到对应的叶子节点,该叶子节点包含了 user_id = 100 的完整行数据。速度极快。

  • 当你执行 SELECT * FROM users WHERE username = 'Alice'; 时,MySQL 使用 idx_username 二级索引。它会在 idx_username 的 B+Tree 中找到 username = 'Alice' 对应的叶子节点。这个叶子节点存储的是 'Alice' 和对应的 user_id 值(假设是 101)。然后,MySQL 会使用 user_id = 101 去聚簇索引中查找完整的行数据(这就是回表)。这个过程比直接通过主键查找多了一步。

  • 当你执行 SELECT user_id, username FROM users WHERE username = 'Alice'; 时,MySQL 仍然使用 idx_username 二级索引。它找到 'Alice' 对应的 user_id (101)。因为查询结果只需要 user_id 和 username,而这两列的值都已经在二级索引的叶子节点中包含了(二级索引叶子节点包含索引列和主键列),所以此时不需要回表 。这种情况称为覆盖索引 (Covering Index),效率很高。

总结:

  • 索引是用于加速查询的数据结构,最常见的是 B+Tree。

  • 索引的种类繁多是因为从不同角度命名:底层结构、逻辑功能、数据关联方式。

  • 在 InnoDB 中,核心是区分 聚簇索引 (数据本身就是索引的一部分,通常是主键) 和 二级索引 (单独的索引结构,叶子节点存主键,需要回表查找数据)。

  • 选择和设计合适的索引是数据库性能优化的关键。需要考虑查询模式、写入频率、存储空间等因素。

相关推荐
间彧1 分钟前
MySQL Exporter采集的关键指标有哪些,如何解读这些指标?
数据库
weixin_4462608511 分钟前
Django - 让开发变得简单高效的Web框架
前端·数据库·django
mpHH25 分钟前
babelfish for postgresql 分析--todo
数据库·postgresql
zizisuo37 分钟前
解决在使用Lombok时maven install 找不到符号的问题
java·数据库·maven
老苏畅谈运维1 小时前
Oracle的connect by level在MySQL中的华丽变身
mysql·oracle
程序边界2 小时前
国产之光!金仓数据库KingbaseES Oracle兼容性深度体验大赏
数据库·oracle
A阳俊yi2 小时前
Spring——声明式事务
java·数据库·spring
A阳俊yi2 小时前
Spring——编程式事务
数据库·sql·spring
编程充电站pro2 小时前
SQL 多表查询常用语法速查:INNER JOIN / LEFT JOIN / RIGHT JOIN
数据库·sql
杨云龙UP3 小时前
SQL Server数据库事务日志问题的诊断与解法(从膨胀到瘦身)
运维·数据库·sql·sqlserver·serverless