你知道多少种索引?

article/2025/9/20 23:49:18

前言

 

嗨,大家好,我是fancy呀。

在工作中我们常常用到索引,无论是普通索引还是唯一索引,都是一些常用的索引方式,目的就是为了提高查询效率,避免业务请求超时等问题。那么,当你在使用索引的时候,是否思考过以下问题:索引是如何实现的,以及一共有哪些索引呢?

带着这些问题,让我们开始吧~ 

什么是索引

不知道你第一次听到索引二字,是否会觉得它非常抽象,且难以理解。索引,什么是索引呢? 索引其实就是一种数据结构。那么在计算机世界中,任何数据结构都有它的用途,如栈、堆、树、队列等。那么,数据库又什么要使用索引?为了提高查询(检索)效率的啦。所以,它就如同书本最前面的目录一样,作用就是作为检索和排序,来极大程度提升你对数据的查询速度。

所以,你可以理解索引是帮助存储引擎高效获取数据的一种方式,就如同你为了高效获取书中的某一块知识而去看书本目录一样。

 

索引的实现方式

索引通常使用的是叫做B树(B Tree)和B+树(B+ Tree)的数据结构。也会使用哈希(Hash)作为索引,这几种方式我们都会聊聊。

B树

B Tree 指的就是 Balance Tree,也就是平衡树。说说它的特点:

  • 它是一颗多路查找树,并且所有叶子节点位于同一层

  • 每个节点中不仅包含数据的键值,还有data值

  • 每个节点都相当于一个磁盘块

你可以对它进行存储数据、对其进行排序,由于是顺序进行读取、插入和删除,所以它的时间复杂度为O(log n)。

 

B+树

B+ Tree是基于B Tree实现的。它具有B Tree的平衡性,并且由于是有序的,也可以通过指针来进行顺序访问,时间复杂度依然为O(log n):

说说它的特点:

  • 每个叶子节存储索引字段的键值及字段对应的数据

  • 非叶子节点只存储索引字段的键值及指向子节点的指针,不存储数据

  • 每个结点相当于一个磁盘块

  • 同一层级的叶子节点之间以双向链表的形式相连

那么,为什么有了B树,还需要B+树呢? 其实,B树和B+树的最大区别就在于:B+树的非叶子节点只会存储指向下一个节点的地址,它并不存储实际的值。并且它所有的叶子节点之间都是使用链表进行连接,由于是有序的,这样进行遍历查找会更快。

所以,B+树就具备了B树不具备的优点。由于非叶子节点不存储数据,在同样空间的内存页当中,就可以存放更多的key,这些key紧密、顺序地排列,对于数据的查询来说会比B树更加稳定和迅速,因为它能够更好地利用空间局部性原理。

Hash

除了B树和B+树,还有一种索引就是哈希了。哈希索引就是基于哈希算法,对于每一行数据,数据库存储引擎会对所有索引列都通过哈希算法去计算一个哈希码,然后将这个哈希码存储在哈希索引中,由于使用的是哈希算法,所以使用哈希索引就会存在两个弊端:

  • 哈希算法计算出来的哈希值可能存在哈希冲突

  • 由于计算出来的是个值所以无法进行范围查询

所以,B树和B+树是数据库中比较常用到的两种索引数据结构,而对于MySQL InnoDB存储引擎来说,它使用的是B+树。

索引的分类

我们刚刚讲解的是索引的实现方式,那么对于索引还能将它以实际的应用功能划分和按照物理实现来进行划分。

按照功能划分

我们平时在写SQL或者建表的时候,会根据实际的业务查询频率、特点和数据量为字段建立各种各样的索引。那么这些索引可以根据实际应用来进行分类:

  • 主键(PRIMARY KEY)

  • 唯一索引(UNIQUE)

  • 普通索引(INDEX)

  • 全文索引(FULLTEXT)

主键

在建表的时候只要指定了主键,就会生成对应的索引。

为什么我这里说主键,而不说主键索引呢。很多人将主键和唯一索引、普通索引这些挂钩在一起,称之为“主键索引”。其实这是不准确的。因为主键本质上来说,它是一种约束,而索引是一种数据结构,用来提升查询效率。两者不是一个层面的东西,也有着功能上质的区别。

在这里我将主键根据功能划分将它放进来,因为它是这些索引 、甚至是一张表的基础,对于MySQL的InnoDB存储引擎来说,一个表结构一定要有一个主键,表中的数据都是按照主键顺序进行存放的。其它索引,也都要依赖于主键来生成索引。

主键的创建方式:

  • 方式1:创建表的时候指定主键,如果创建表时没有显示定义主键,InnoDB就会通过以下规则去创建一个主键:

判断表中是否存在一个非空的唯一索引。如果存在,则该索引对应的字段名即为主键。如果不存在,则InnoDB会自动创建索引

  • 方式2:通过SQL语句:

ALTER TABLE `table_name` ADD PRIMARY KEY `column_name`;

那们,我们常常说的“主键索引”又是怎么一回事呢?一会我们就会接触到。

唯一索引

唯一索引就是作为一种索引,可以确保这行索引列不包含重复的值。所以它和非唯一索引的区别就是除了具有索引的功能,还限制这一字段在数据库中不能有重复记录,我们可以通过以下SQL创建唯一索引:

ALTER TABLE `table _name` ADD UNIQUE indexName;

普通索引

朴实无华,最普通的索引类型了。将一个或者多个字段添加索引,仅仅用来增加查询速度。fancy在工作中创建最多的就是普通索引了。它的创建语句:

ALTER TABLE `table_name` ADD INDEX index_name;

全文索引

作为程序员,我们每日都要和搜索引擎打交道了。不仅仅是搜索引擎,在很多app上,都有一个全文搜索的功能:

如果不去使用一些中间件技术,我们的每一次搜索,都要去根据关键词去数据库中查找。

如果不使用索引,那么在海量的数据里面要将你预期的结果筛选出来,可能要花费好几秒的响应时间。这对于用户来说无疑是不可接受的。

所以,全文索引,就适合应用于这样的业务场景。

如果想要使用全文索引,就必须指定存储引擎为MYISAM,因为InnoDB存储引擎是不支持全文索引的。

由于全文索引存在许多弊端,比如不支持大小写、索引创建慢等问题,所以不建议使用MySQL的全文索引。在现在的场景中,我们一般使用ElasticSearch这种封装好的中间件来满足全局数据检索的需求。全文索引创建的方式:

ALTER TABLE `table_name` ADD FULLTEXT `column`;

按照索引数量划分

如果一个索引加在一个字段上,那么它就是一个单列索引。但是我们也可以将多个字段联合起来一起创建一个索引,这种索引就被称为“联合索引”,也叫多列索引或者组合索引。为了方便起见。我们之后都统一叫做“联合索引”

注:多个单列索引并不能被称为组合索引

之后,我们会单独地详细讲讲这个联合索引,以及它产生的一些问题,所以本文先不过多描述。

按照物理实现划分

为了帮助大家更好理解,我们现在创建一张表:

create table fancyFamily(id int(11) not null auto_increment comment '家庭成员ID',name varchar(16) not null comment '家庭成员名字',age int(11) default null comment '家庭成员年龄',primary key (id)) engine InnoDBAUTO_INCREMENT = 10default charset = utf8;

然后插入一定的数据量:

 insert into fancyFamily(id, name, age) values (1, 'fancy', 26);insert into fancyFamily(id, name, age) values (3, '小黄', 25);insert into fancyFamily(id, name, age) values (8, '大粉', 50);insert into fancyFamily(id, name, age) values (10, '大黄', 55);insert into fancyFamily(id, name, age) values (13, '小蓝', 18);insert into fancyFamily(id, name, age) values (16, '小白', 15);

聚集索引

什么是聚集索引?我们刚刚说过,对于一颗以B+树为数据结构创建的索引,只有叶子节点中存放数据,并且叶子节点中的数据都是按照数据库表中的数据一行一行进行连续排列的:

我们就将一颗满足于以上数据存储形式的索引形式,称之为“聚集索引”。这里注重的是数据的存储形式,也就是将数据存储在叶子节点中。

并且由于一张表中的数据无法存放于两颗不同的B+树中。所以一张表也只能有一个聚集索引

那我们现在就存在一个问题了:一张表中只能有一个主键,也只能有一个聚集索引,并且聚集索引还是按照B+树中主键的数据存放形式来生成的,那么聚集索引不就是主键吗?

还是上文提到的知识点:主键是一种约束,用来完善表结构的数据完整性。而聚集索引是一种索引,目的就是将数据建立成有序的以便于减少查询的时间复杂度。它是一种索引,而索引的用途就是用来提升查询效率的。就像是你买房和买车一样,它们之间的用途就有着本质的区别。

那“主键索引”这个词,又是怎么一回事呢?在InnoDB存储引擎中,一张表一定会存在一个主键,它是索引能够被用来提升效率的基础,只有拥有主键才能进行排序和查询。而只有建立了主键,才能够生成聚集索引这种数据存储形式,所以当一张表的主键生成式,其对应的聚集索引也便生成了。所以有人也喜欢将聚集索引称为“主键索引”。

辅助索引

有了聚集索引,就会有非聚集索引。除了聚集索引之外的索引都叫做非聚集索引,比如以某非主键的字段创建索引后构建起来的索引树。它也叫二级索引或者辅助索引,为了方便起见,我们之后都将其称为辅助索引。

那么它和聚集索引的区别是什么呢?最大的区别就是聚集索引的叶子结点是包含表结构的全部行数据的,但是辅助索引并不包含。

它依然使用B+树,只是每个叶子节点存储的是聚集索引所在列的主键值:

 

不同于聚集索引,由于其不按照主键进行排列检索,所以一张表中可以存在多个主键索引。

那么,如果我们现在创建了name这个辅助索引,并且去查询小黄这个名字,它会怎么操作呢?

select * from workers where name='小黄';

它的查询步骤如下:

  • 通过name=’小黄‘这个条件去辅助索引找到对应的叶子节点的键值

  • 找到'小黄'对应的数据,也就是小黄这行数据对应的主键

  • 通过这个主键,返回聚集索引

  • 通过聚集索引的主键排序,去叶子节点找到主键ID为3的小黄对应的数据

也就是说,如果使用辅助索引,它不会像主键索引那样直接去叶子节点找对应的数据,而是先去叶子节点找到对应条件的主键,再返回聚集索引根据这个主键去搜索一遍。这种情况我们称为回表

 也就是说,如果使用了辅助索引,是要比聚集索引多一次树的访问和遍历的。

总结

以上我们描述了什么是索引、索引的实现方式、和索引的具体分类。通过索引的功能、数量、和物理实现可以区分为不同的索引,也具体描述了聚集索引和非聚集索引的区别。

在我身边有工作了很多年的同事,他们业务能力有的一级棒,但是在讲到数据库的索引也会出现不够清晰的划分和总结,所以我觉得将这些基础知识理清十分重要。本篇是关于索引的第一篇,在之后我们还会陆续为大家带来索引其它知识的具体讲解~

我是fancy,如果觉得本篇还不错,麻烦关注点赞支持一下呀!


http://chatgpt.dhexx.cn/article/1GMQX694.shtml

相关文章

动态规划算法 | 最长递增子序列

通过查阅相关资料发现动态规划问题一般就是求解最值问题。这种方法在解决一些问题时应用比较多,比如求最长递增子序列等。 有部分人认为动态规划的核心就是:穷举。因为要求最值,肯定要把所有可行的答案穷举出来,然后在其中找最值…

求最长递增子序列个数——C++

声明:本文原题主要来自力扣,记录此博客主要是为自己学习总结,不做任何商业等活动! 一、下面是原题描述 给定一个未排序的整数数组,找到最长递增子序列的个数。 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递…

最长递增子序列(LIS)

最长递增子序列(LIS) 问题描述: 求一个序列的最长递增子序列,这样的子序列是允许中间越过一些字符的,即留“空”。 例如:4 2 3 1 5 的最长递增子序列为 2 3 5,长度为 3 。 解法:…

【Leetcode】最长递增子序列问题及应用

文章目录 最长递增子序列问题及应用300. 最长递增子序列面试题 17.08. 马戏团人塔354. 俄罗斯套娃信封问题面试题 08.13. 堆箱子1691. 堆叠长方体的最大高度406. 根据身高重建队列 最长递增子序列问题及应用 300. 最长递增子序列 请参考 【Leetcode】计算最长系列&#xff08…

输出最长递增子序列

目录 题目: 输入描述: 输出描述: 示例1 输入 输出 示例2 输入 输出 说明 备注: 思路分析: 改进: 得到最长子序列: 易错点: 代码展示: 题目: 给定数组arr,设长度为n&…

NC91 最长递增子序列

NC91 最长递增子序列 这道题n的范围是1e5,因此不能使用常规的dp[i],表示以i结尾的最大的子序列,因为这个时间复杂度是n方级别。因此要换一种算法。 贪心二分,时间复杂度为O(nlogn) 下面说说贪心二分的解法,举例说明基…

Vue3 最长递增子序列详解

Vue3 最长递增子序列研究 本文初衷 彻底讲清楚 Vue3 源码中实现最长递增子序列的算法。 概念名词 **最长递增子序列:**在一个给定的数值序列中,找到一个子序列,使得这个子序列元素的数值依次递增,并且这个子序列的长度尽可能地…

Java 最长递增子序列_最长递增子序列问题 Java

最长递增子序列问题 LIS(longest increasing subsequence) 例如 给定一个数列,长度为N, 求这个数列的最长上升(递增)子数列(LIS)的长度. 以 1, 7, 2, 8, 3, 4 为例。 这个数列的最长递增子数列是 1 2 3 4,长度为4; 次长的长度为3&…

最长递增子序列

问题 给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4. 解法1:最长公共子序列法 这个问题可以转换为最长公共子序列问题。如…

动态规划设计方法详解最长递增子序列

很多读者反应,就算看了前文动态规划详解,了解了动态规划的套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学归纳思想。 最长递增…

最长递增子序列(Longest Increasing Subsequence)

定义 最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。 问题描述 给定一个长度为 N 的数组,找出一个最长的单调自增子序列(不一定连续&#…

最长递增子序列问题(你真的会了吗)

目录 一.最长递增子序列问题I 二.最长递增子序列问题II 三. 最长递增子序列问题III 一.最长递增子序列问题I 1.对应牛客网链接 最长上升子序列(一)_牛客题霸_牛客网 (nowcoder.com) 2.题目描述: 3.解题思路 1.首先我们分析题意:最长递增子序列拆&#x…

UDP协议详细解析

一、基本概念 基本定义:UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的…

tcp read 和 udp recvfrom

udp中写一个长度为0的数据报是可行的,这导致一个包含IP头部、udp头部和没有数据的IP数据报。这也意味着对于数据报协议,recvfrom返回0值也是可行的:它不表示对方已经关闭了连接,这与tcp套接口上read返回0值的情况不同。由于udp是无…

UDPTCP

目录 Socket 一.UDP 特点 基于UDP实现回显服务器 服务器 客户端 端口冲突 图解 二.TCP 特点 基于TCP实现回显服务器 服务器 客户端 图解 Socket Socket套接字,是由系统提供用于网络通讯的技术,是基于TCP/IP协议的网络通信的基本操作单元,基于…

Reliable UDP

Reliable UDP(可靠的UDP)是一套服务品质的增强,比如拥挤控制调整,数据重传,薄化服务器算法等,这些增强可以提高服务器在数据包丢失和网络拥挤的条件下向RTP客户表现品质良好的RTP流的能力。Reliable UDP’的…

TCP /UDP

TCP与UDP工作在传输层,在程序之间传数据(视频,聊天,图片,网页) TCP基于连接的,可靠的(及时知对方接受/拒绝,是否传错)(文本,网页&…

UDP、TCP

传输层协议UDP、TCP 一、TCP/UDP的任务二、UDP1.UDP概述2.UDP报文格式3.使用UDP的应用层协议 三、TCP1.TCP概述2.TCP报文3.TCP三次握手4.四次挥手5.超时重传6.流量控制和快重传7.拥塞控制8.延迟应答、捎带应答9.粘包问题10.基于TCP的应用层协议 四、总结 一、TCP/UDP的任务 我们…

tcp udp proxy

服务目的 首先如下图所示: 作为一个内外网的通信,必须使用tcp 和 udp 的proxy 把内网和外网打通,比如中间是一个有两个网卡的路由器,打通以后,由proxy 发送数据到服务端,服务端按照上图处于外网。 服务端…

UDP-RTP协议解析

一、RTP协议 数据传输协议RTP,用于实时传输数据。RTP报文由两部分组成:报头和有效载荷 二、RTP的会话过程 当应用程序建立一个RTP会话时,应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成,有两个端口&a…