2026/4/18 17:21:07
网站建设
项目流程
西安网站seo费用,wordpress页面不加载主题js,最受欢迎国内设计网站,山东企业网站建设目录
一、前言
二、索引类型划分
三、按功能/约束分类
1.主键索引#xff08;PRIMARY KEY#xff09;
2.唯一索引#xff08;UNIQUE#xff09;
3.常规索引#xff08;普通索引 / INDEX#xff09;
4.全文索引#xff08;FULLTEXT#xff09;
四、按“存储形式…目录一、前言二、索引类型划分三、按功能/约束分类1.主键索引PRIMARY KEY2.唯一索引UNIQUE3.常规索引普通索引 / INDEX4.全文索引FULLTEXT四、按“存储形式/数据组织方式”分类1.聚簇索引聚集索引2.非聚簇索引五、图解六、关联七、问题八、总结一、前言索引是一种用于快速查询和检索数据的数据结构其本质可以看成是一种排序好的数据结构。索引的作用就相当于书的目录。打个比方我们在查字典的时候如果没有目录那我们就只能一页一页地去找我们需要查的那个字速度很慢如果有目录了我们只需要先去目录里查找字的位置然后直接翻到那一页就行了。索引底层数据结构存在很多种类型常见的索引结构有B 树、 B 树 和 Hash、红黑树。在 MySQL 中无论是 Innodb 还是 MyISAM都使用了 B 树作为索引结构。二、索引类型划分按照数据结构维度划分BTree 索引MySQL 里默认和最常用的索引类型。只有叶子节点存储 value非叶子节点只有指针和 key。存储引擎 MyISAM 和 InnoDB 实现 BTree 索引都是使用 BTree但二者实现方式不一样前面已经介绍了。哈希索引类似键值对的形式一次即可定位。RTree 索引一般不会使用仅支持 geometry 数据类型优势在于范围查找效率较低通常使用搜索引擎如 ElasticSearch 代替。全文索引对文本的内容进行分词进行搜索。目前只有CHAR、VARCHAR、TEXT列上可以创建全文索引。一般不会使用效率较低通常使用搜索引擎如 ElasticSearch 代替。按数据结构维度划分的索引类型本文不做详细介绍本文主要针对以下两种分类做阐述按“功能/约束”分类主键索引、唯一索引、常规索引、全文索引分类含义特点关键字主键索引针对于表中主键创建的索引默认自动创建, 只能有一个PRIMARY唯一索引避免同一个表中某数据列中的值重复可以有多个UNIQUE常规索引快速定位特定数据可以有多个全文索引全文索引查找的是文本中的关键词而不是比较索引中的值可以有多个FULLTEXT按“存储形式/数据组织方式”分类聚集索引Clustered、二级索引Secondary分类含义特点聚集索引(Clustered Index)将数据存储与索引放到了一块索引结构的叶子节点保存了行数据必须有,而且只有一个二级索引(Secondary Index)将数据与索引分开存储索引结构的叶子节点关联的是对应的主键可以存在多个三、按功能/约束分类1.主键索引PRIMARY KEY定义表的“主键”对应的索引MySQL 用它来唯一标识一行数据。一张表只能有一个主键主键列不能为 NULL并且必须唯一。InnoDB 特点InnoDB 中主键索引 聚集索引后面会解释聚集索引是什么。也就是说数据行本身就“存”在主键索引的 BTree 叶子节点里。适用场景绝大多数表都应该设计主键自增 id、雪花 id、UUID不推荐随机 UUID 做主键容易导致页分裂/碎片。必须为表指定主键如无显式定义InnoDB 会自动生成隐藏主键。常用于WHERE user_id 1001或联表查询。CREATE TABLE users ( id INT PRIMARY KEY, -- 主键索引 username VARCHAR(50) );2.唯一索引UNIQUE定义约束某列/多列的值必须唯一。限制列值不能重复但大多数情况下允许 NULL且多个 NULL 在 MySQL/InnoDB 中通常是允许的。一张表可以有多个唯一索引。底层实现InnoDB 下通常也是BTree。与普通索引的核心差别写入时会做唯一性校验。典型用途既是“约束”保证不重复也是“加速器”加速查询常用于手机号、邮箱、业务唯一编号用户表username、email业务表的唯一业务号如order_no。CREATE TABLE users ( id INT PRIMARY KEY, mobile VARCHAR(20) UNIQUE, -- 唯一索引 email VARCHAR(50) UNIQUE );3.常规索引普通索引 / INDEX定义最基本的索引只用于加速查询没有唯一性约束。底层实现InnoDB一般是BTree 二级索引后面会讲“二级索引”。特点最常用按条件查、排序、范围查询、JOIN可以是单列索引也可以是联合索引复合索引用途频繁作为WHERE条件、JOIN条件、ORDER BY、GROUP BY的列。支持WHERE status paid或ORDER BY create_time。例子单列索引ALTER TABLE user ADD INDEX idx_name(name);例子联合索引ALTER TABLE user ADD INDEX idx_name_phone(name, phone);查询SELECT * FROM user WHERE nameTom AND phone138...; 更容易走(name, phone)的联合索引。4.全文索引FULLTEXT定义InnoDB 从 MySQL 5.6 开始支持 FULLTEXT历史上 MyISAM 更早支持。适合分词 相关性排序用来做“文本检索”支持对长文本按词或按分词搜索例如MATCH(col) AGAINST(...)。实现与特点InnoDB 的 FULLTEXT 是专门的倒排索引体系不是 BTree。更适合文章、评论、商品描述等“文本搜索”。注意中文检索通常需要分词支持MySQL 原生能力有限很多场景会用 Elasticsearch 等专用搜索引擎。例子CREATE TABLE article ( id BIGINT PRIMARY KEY, title VARCHAR(200), content TEXT, FULLTEXT KEY ft_content(content) ) ENGINEInnoDB;查询SELECT * FROM article WHERE MATCH(content) AGAINST(mysql 索引 IN NATURAL LANGUAGE MODE);四、按“存储形式/数据组织方式”分类1.聚簇索引聚集索引聚簇索引在 InnoDB 存储引擎中聚簇索引通常就是主键索引 。聚簇索引的特点是数据与索引一体化存储即数据行整行不是指针直接存储在索引的叶子节点中并且数据按照主键的顺序进行物理存储 。这使得聚簇索引在查询时具有极高的效率尤其是对于主键查询和范围查询。因为数据是按照主键顺序存储的所以在进行范围查询如查询 ID 在某个范围内的用户时可以利用索引的有序性快速定位到满足条件的数据。此外聚簇索引还能利用顺序检测预取机制提高数据读取的效率。例如在一个用户表中以用户 ID 为主键创建聚簇索引当查询用户 ID 为 100 的用户信息时数据库可以直接通过聚簇索引找到对应的叶子节点获取用户信息无需进行额外的查找操作。需要注意的是一张表只能有一个聚簇索引因为数据的物理存储顺序只能有一种。概括:用主键查 直接定位到叶子节点 一次 BTree 查找拿到整行。为什么叫“聚集”因为数据行与索引键“聚在一起”数据就是索引的一部分。聚集索引选取规则:如果存在主键主键索引就是聚集索引。如果不存在主键将使用第一个唯一UNIQUE索引作为聚集索引。如果表没有主键或没有合适的唯一索引则InnoDB会自动生成一个rowid作为隐藏的聚集索引。聚簇索引的优缺点优点查询速度非常快聚簇索引的查询速度非常的快因为整个 B 树本身就是一颗多叉平衡树叶子节点也都是有序的定位到索引的节点就相当于定位到了数据。相比于非聚簇索引 聚簇索引少了一次读取数据的 IO 操作。对排序查找和范围查找优化聚簇索引对于主键的排序查找和范围查找速度非常快。缺点依赖于有序的数据因为 B 树是多路平衡树如果索引的数据不是有序的那么就需要在插入时排序如果数据是整型还好否则类似于字符串或 UUID 这种又长又难比较的数据插入或查找的速度肯定比较慢。更新代价大如果对索引列的数据被修改时那么对应的索引也将会被修改而且聚簇索引的叶子节点还存放着数据修改代价肯定是较大的所以对于主键索引来说主键一般都是不可被修改的。2.非聚簇索引也称为二级索引其索引存储的是主键值而不是实际的数据行 。当使用非聚簇索引进行查询时首先会根据索引找到对应的主键值然后再通过主键值在聚簇索引中查找实际的数据行整行这个过程称为回表查询 。非聚簇索引支持多列组合索引适用于多个字段联合查询的场景。例如在一个订单表中经常需要根据客户 ID 和订单日期进行查询可以为客户 ID 和订单日期创建组合非聚簇索引。虽然非聚簇索引需要回表查询查询效率相对聚簇索引略低但在某些情况下它可以提供更灵活的查询方式。比如在查询订单表中某个客户在特定日期之后的订单时通过组合非聚簇索引可以快速定位到满足条件的主键值然后再通过回表查询获取完整的订单信息。概括二级索引的叶子节点存的不是整行而是“索引列 主键值”。覆盖索引避免回表如果查询需要的列都在二级索引里或索引里包含它们那就不需要回表这叫覆盖索引。例如select name from user where age20;若建了(age, name)联合索引就可能直接从索引叶子拿到name无需回表。非聚簇索引的优缺点优点更新代价比聚簇索引要小。非聚簇索引的更新代价就没有聚簇索引那么大了非聚簇索引的叶子节点是不存放数据的。缺点依赖于有序的数据跟聚簇索引一样非聚簇索引也依赖于有序的数据。可能会二次查询回表这应该是非聚簇索引最大的缺点了。当查到索引对应的指针或主键后可能还需要根据指针或主键再到数据文件或表中查询。五、图解1.示例表结构CREATE TABLE account_example ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 账户ID, name VARCHAR(20) COMMENT 姓名, money DOUBLE(10,2) COMMENT 余额, INDEX idx_name (name), INDEX idx_name_money (name, money) ) ENGINEInnoDB; -- 插入数据 insert into account_example(id, name , money) values (1, 张三, 100.00), (3, 李四, 200.00), (7, 王五, 300.00);id→主键索引聚簇索引idx_name(name)→普通二级索引idx_name_money(name, money)→ 联合索引2.聚簇索引idBTree 示意图聚簇索引的BTree 的叶子节点存放的是整行数据。特点总结一张表只能有一个聚集索引数据行按主键顺序物理存储使用主键查询SELECT * FROM account WHERE id 3; 一次 BTree 查找即可拿到整行数据不存在回表3.非聚簇索引idx_name的 BTree 示意图非聚簇索引的叶子节点中不存整行数据只存「索引列值 主键值」二级索引的叶子节点下挂的是该字段值对应的主键值。4.为什么会发生回表示例 SQL会回表SELECT * FROM account WHERE name 李四;执行过程拆解Step 1通过二级索引 idx_name 查找name李四 ↓ 在 idx_name BTree 中定位 ↓ 得到主键 id 3Step 2根据主键回到聚集索引id3 ↓ 在 PRIMARY KEY BTree 中查找 ↓ 获取完整行数据这一步称为回表本质原因二级索引不存完整数据5.联合索引 idx(name, money) 的存储结构联合索引叶子节点存(name, money) ididx_name_money(name, money) BTree 示意图6.覆盖索引 vs 回表❌ 示例 1需要回表SELECT * FROM account WHERE name 李四;使用idx_namemoney 不在索引中必须回表✅ 示例 2覆盖索引不回表SELECT name, money FROM account WHERE name 李四;使用idx_name_money查询字段全部存在索引叶子节点无需回表 这就叫覆盖索引Covering Index7.总结场景是否回表原因where id ?❌聚集索引叶子节点存整行普通二级索引查 *✅二级索引不存完整数据联合索引覆盖查询字段❌查询字段都在索引中SELECT *几乎一定字段太多无法覆盖六、关联功能分类在 InnoDB 的存储形式主键索引聚集索引叶子存整行唯一索引通常是 二级索引除非它被选为聚集索引键常规索引二级索引全文索引倒排索引体系不按聚集/二级的 BTree 逻辑走七、问题主键为什么不要用随机值如随机 UUID聚集索引决定了数据行的物理组织顺序随机插入会导致频繁页分裂、碎片、写放大性能更差 自增/有序主键插入更“顺滑”二级索引为什么存主键值而不是物理地址因为 InnoDB 的数据行会移动/页会分裂存物理地址维护成本高存主键值更稳定代价是可能需要回表建索引的常见收益点加速WHERE、JOIN、ORDER BY、GROUP BY利用覆盖索引减少回表、减少 IO八、总结InnoDB 中主键索引就是聚集索引数据行存放在主键 BTree 的叶子节点二级索引的叶子节点只保存索引列和主键值因此在查询非索引字段时需要回表当查询字段完全被索引覆盖时可以避免回表从而显著提升查询性能。