MySQL数据库操作篇5(索引的原理及用法)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MySQL数据库操作篇5(索引的原理及用法)

索引是MySQL中的一大利器,这篇文章旨在讲清楚什么是索引,索引的底层实现原理是什么,使用索引能带来哪些好处,以及索引如何使用较好

此文章会用到前面提到过的一些术语,比如元组,一个元组就指表中的一行数据


什么是索引

通过前面的学习,我们了解过,在数据库中创建一个表,我们就可以往表中插入数据,然后需要数据的时候在表中查找就行了,普通用户可以直接使用数据库设计者提供的功能,不用关心如何实现查找,作为程序开发人员,我们需要关心这个问题。前面我们讲了很多MySQL中查找数据的方法,但是这些查找总得有个底层的算法实现吧,我们最容易想到的查找算法是遍历,把表中所有的数据都遍历一遍,不就可以查到想要的数据了嘛

对于小批量的数据,确实可以这么做,但是数据库就是存放大批量数据的,一张表中可能有几万行数据,如果这个时候还使用遍历查找,那么查找效率会非常的低,为了解决这个问题,数据库设计者就提出了索引这个概念,所以索引就是来解决数据查找效率的问题的

索引的实现是靠比较优秀的查找算法,不用加内存,不用改程序,不用调sql,只要执行

正确的 create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度


索引的底层实现原理

搞明白索引是干嘛的,有什么用之后,我们接着来看,如何实现索引。为了更透彻的理解索引,此篇文章要从硬件和软件两个方面同时介绍。

查找过程本质就是在做排除,把无用数据排除在外,高效率的查找就是在较短的时间内,排除掉尽可能多的数据,要做到这一点,就需要我们人为把数据分配整齐,想一想我们按照类别给数据进行划分,只需要去待查找数据的所属类别里查找即可,此时其他所有的类别就都被排除掉了。

例如我们书本中常见的目录就是一种高效的查询方式,书本根据内容的不同,划分为几个章节,目录中记录着这些章节的具体页码,当想要查找某个信息时,只需要去该信息所属的那个章节即可,而其他的章节在这个查找过程中就被排除掉了,这样就能很快查到信息,比遍历一本书要快速很多,索引的实现原理就类似于此

我们先来了解MySQL与磁盘的交互,关于磁盘的内容,笔者在Linux的IO篇里详细的讲解了,如果不明白磁盘工作原理的,请移步查看。操作系统每次与磁盘IO的大小是4kb。大家可以想想,每次4kb字节的IO,对于操作系统来说可能就够用了,但是对于数据库来说,小了一些,因为数据库中存放的数据是相当大的,因此数据库需要与磁盘一次IO更多,根据实践,数据库一次与磁盘进行16kb的IO是比较好的

但是之前我们了解过,只有操作系统才能够和硬件进行交互,而数据库本质是属于应用层的,所以它没有权利和磁盘直接进行IO,它与磁盘的IO操作要依托操作系统来完成

MySQL创建表本质就是创建一个文件,所以MySQL与操作系统进行交互时,也是通过文件来进行的,如上图,MySQL会申请一个缓冲区用来存取与OS进行IO操作的数据

这个过程是麻烦的,我们在逻辑上可以忽略OS这个角色,认为MySQL直接与磁盘进行IO操作,且一次16kb大小,也就是说MySQL 和磁盘进行数据交互的基本单位是 16KB 。这个基本数据单元,在 MySQL 这里叫做page(注意和系统的page区分)

为什么要提到page呢?因为MySQL 中的数据文件,是以page为单位保存在磁盘当中的,一张表,也就是一个数据文件,是由一个或者多个page构成的。MySQL中的数据文件以page为单位,势必会造成存储空间不能完全利用的情况,为什么要以page为单位,而不是存多少用多少呢?这就涉及到IO的效率了,我们都知道与磁盘的IO效率是很低的,如果一次以表中一个元组(表中的一行)的大小为单位,那么在查找时,有100个元组就要进行100次IO操作,而使用page为单位,一次IO就可以把100个元组的数据都加载进内存

各个page之间通过双向链表连接起来,每个page里包含着所存的数据内容,同时也有指向前一个和后一个page的指针

大家可以想一想,如果一个page里存满了数据,那么在一个page里查找数据,如果使用线性遍历的方法进行查找的话,效率会很低,还记得我们前面的提到过比较高效的目录形式吗?为了提高在一个page中遍历的效率,我们可以将page中的数据先按顺序进行一个排序,排完序之后再将其按照序号划分成目录,就拿上面这个page为例来进行划分,划分结果如下图

这里数据量比较小,不过不影响我们理解这种思想,假设查找id为4的人是谁,大致过程为在目录区中使用二分法查找id为4属于哪个目录,图中只有两个目录,第二个目录标记的最大id值为3,因为4>3,我们就从目录二进入到id为3的数据,然后向下移动一位,就找到了id为4的数据,随后返回结果即可。这里数据量很小,效果并不明显,随着数据量增大,这种查询算法的优势愈加明显

当然,我们前面说过一张表可能有一个page或者多个page构成,为了展示整张表的全貌,这里假设一个page只能存放五个元组,MySQL中一张表的存储结构大致如下(为了作图方便,数据中人物的名字是重复的,只关注数据的id序号即可)

理解完上面的内容,接下来还得思考一些问题,数据库就是用来存放数据的,那么大量的数据势必会造成page数目的剧增。我们前面解决的是如何在一个page内部高效的查找数据,当page数目变得非常多的时候,我们就得考虑,如何在page和page之间进行高效的查找,以上图为例,假设我们要查找id值为14的全部数据,那么会先加载第一个page,通过内部的查询后发现不在该page里,于是加载第二个page,通过内部的查询后发现不在该page里,于是加载第三个page,终于在内部查询到了,返回查询结果

将每一个page加载到内存,进行线性检测。这样就显得我们之前的page内部的目录,有点杯水车薪了,那么如何解决呢?解决方案,其实就是我们之前的思路,给page也带上目录

使用一个目录项来指向某一页,这个目录项存放的是将要指向的页中存放的最小数据的键值

和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行

其中,每个目录项的构成是:键值+指针

大致过程如下图

将page也放到一个目录中,这样就不用怕随着page数目的增多,查询效率低下的问题了

在上图中最下层,存放着真实数据的页,我们称之为普通页,而第二层,标志普通页的目录的页我们称之为目录页,目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址

虽然目录页改善了普通页的查找效率,但我们每次检索数据的时候,该从哪里开始呢?虽然顶层的目录页少了,但是还要遍历啊?不用担心,我们还可以给目录页再加一层目录页

大致操作如下图

过这三层目录结构的搭配使用,查找数据的效率将会变得非常之高,这个结构其实就是B+树, 也是索引的底层实现原理,不过这并不意味着,所有的数据库的索引都是靠B+树来实现的,这取决于数据库使用的存储引擎,我们常用的InnoDB使用的就是B+树来实现,也有的存储引擎使用B树,使用哈希等结构,根据不同的应用场景来选择合适的


B树 VS B+树

B树和B+树都是常用的数据结构,也是MySQL数据库都支持的结构形式,不同的存储引擎所使用的数据结构都不尽相同,这里简单展示一下B树和B+树是如何在数据库中应用的,以及两者之间的区别,关于这两种数据结构如何创建,笔者将会在数据结构栏里详谈

下图是B树的结构图

下图是B+树的结构图


聚簇索引 vs 非聚簇索引

在使用索引时,我们可能经常会听到聚簇索引和非聚簇索引这些概念,这些具体指代的是什么呢?如下图,在这个B+树索引中,叶子节点存放的并不是数据,而是数据在内存上的指针,通过这个指针就可以找到数据,大家可以发现,在这个过程中,数据就和索引结构分离开了,像这样的索引方案,我们就称之为非聚簇索引

在下面这张图中,B+树的叶子节点存放的就是数据本身,而不是数据的指针,像这样索引结构和数据放在一起的我们就称之为聚簇索引

InnoDB是采用聚簇索引,MyISAM采用的是非聚簇索引,不过这两个存储引擎的索引结构均是B+树,你可能好奇,为什么要分成聚簇索引和非聚簇索引呢?下面就是两者各自的优缺点

聚簇索引的优点:

 聚簇索引将数据行物理上按照索引的顺序存储在磁盘上,因此对于按索引列进行范围查询或排序的操作,聚簇索引可以提供更高的查询性能

 聚簇索引可以减少磁盘I/O操作,因为相邻索引键值的数据行通常在磁盘上也是相邻存储的,减少了磁盘读取的次数

 聚簇索引可以节省存储空间,因为数据行按照索引顺序存储,可以减少数据行中重复的索引列的存储

聚簇索引的缺点:

 聚簇索引的维护代价相对较高。当插入或删除数据时,因为数据行的物理存储顺序可能需要进行调整,所以维护聚簇索引的代价较高

 聚簇索引一般只能创建在唯一键或主键上,对于非唯一键的查询性能可能较差

非聚簇索引的优点:

 非聚簇索引的维护成本相对较低。当插入或删除数据时,不需要调整数据行的物理存储顺序,因此维护非聚簇索引的代价较低

 非聚簇索引可以创建在任意列上,不限唯一键或主键。可以提供对非唯一键的高效查询

非聚簇索引的缺点:

 非聚簇索引的查询性能可能较低。因为数据行在磁盘上的物理存储顺序与索引顺序不一定一致,对于范围查询或排序操作,可能需要进行更多的磁盘I/O操作

 非聚簇索引通常需要占用更多的存储空间,因为索引结构中需要存储索引列的值和指向数据行的指针。 根据具体的应用场景和查询需求,选择合适的索引类型可以提高数据库的查询性能。聚簇索引适用于经常进行范围查询或排序的列,而非聚簇索引适用于非唯一键或不经常进行范围查询的列。


需要大家注意的是,聚簇索引一定要有唯一键索引,也就是主键索引,如果自己没有设置,MySQL会默认设置,除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引,关键点来了,普通索引的叶子节点可不像主键索引那样存放着数据,而是存放着对应的主键值,拿到这个主键值后,还要回过头根据这个主键值,再去查一遍主键索引,最终找到数据,这个过程叫做回表查询,这也是为什么强调聚簇索引一定要有主键索引的原因。为什么不把普通索引的叶子节点也放上数据呢?因为主键所引上已经存放数据了,再存放一次就会造成数据的重复,空间的极大浪费


索引的相关操作

了解完索引是什么,以及索引的底层实现原理之后,我们接下来进入实操环节,看看如何在MySQL中创建和使用索引,在创建数据库时要根据未来的需求来确定采用哪种存储引擎,默认情况下都是采用InnoDB存储引擎

1.创建主键索引

在InnoDB中会默认根据主键创建主键索引,故而只需要指明主键即可

1.-- 在创建表的时候,直接在字段名后指定 primary key

create table test(id int primary key, name varchar(30));

在InnoDB中会默认根据主键创建一个主键索引

2.-- 在创建表的最后,指定某列或某几列为主键索引

create table test(id int, name varchar(30), primary key(id));

3.create table test(id int, name varchar(30));

-- 创建表以后再添加主键

alter table test add primary key(id);

主键索引的特点:

一个表中,最多有一个主键索引,当然可以使符合主键

主键索引的效率高(主键不可重复)

创建主键索引的列,它的值不能为null,且不能重复

主键索引列的数据类型基本上是int,有利于数据内容的排序和划分


2.创建唯一键索引

在InnoDB中会默认根据唯一键创建唯一键索引,故而只需要指明唯一键即可

1. -- 在表定义时,在某列后直接指定unique唯一属性。

create table test(id int primary key, name varchar(30) unique);

2.-- 创建表时,在表的后面指定某列或某几列为unique

create table test(id int primary key, name varchar(30), unique(name));

3.create table test(id int primary key, name varchar(30));

-- 创建表以后再添加唯一键

alter table test add unique(name);

唯一索引的特点:

一个表中,可以有多个唯一索引

查询效率高

如果在某一列建立唯一索引,必须保证这列不能有重复数据

如果一个唯一索引上指定not null,等价于主键索引


3.创建普通索引

1.create table test(id int primary key,

name varchar(20),

email varchar(30),

index(name) --在表的定义最后,指定某列为索引

);

2.create table test(id int primary key,

name varchar(20),

email varchar(30),

);

alter table user9 add index(name); --创建完表以后指定某列为普通索引

3.create table test(id int primary key,

name varchar(20),

email varchar(30),

);

-- 创建一个索引名为 idx_name 的索引

create index idx_name on test(name);

普通索引的特点:

一个表中可以有多个普通索引,普通索引在实际开发中用的比较多

如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引


索引的查询

第一种方法: show keys from 表名
第二种方法: show index from 表名;
第三种方法(信息比较简略):desc 表名;


删除索引

第一种方法-删除主键索引: alter table 表名 drop primary key;

第二种方法-其他索引的删除: alter table 表名 drop index 索引名;

索引名就是show keysfrom 表名中的 Key_name 字段

第三种方法方法: drop index 索引名 on 表名


索引创建原则

比较频繁作为查询条件的字段应该创建索引
唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
更新非常频繁的字段不适合作创建索引
不会出现在where子句中的字段不该创建索引

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
20天前
|
数据库 索引
深入探索数据库索引技术:回表与索引下推解析
【10月更文挑战第15天】在数据库查询优化的领域中,回表和索引下推是两个核心概念,它们对于提高查询性能至关重要。本文将详细解释这两个术语,并探讨它们在数据库操作中的作用和影响。
43 3
|
20天前
|
数据库 索引
深入理解数据库索引技术:回表与索引下推详解
【10月更文挑战第23天】 在数据库查询性能优化中,索引的使用是提升查询效率的关键。然而,并非所有的索引都能直接加速查询。本文将深入探讨两个重要的数据库索引技术:回表和索引下推,解释它们的概念、工作原理以及对性能的影响。
42 3
|
6天前
|
数据库 索引
数据库索引
数据库索引 1、索引:建立在表一列或多列的辅助对象,目的是加快访问表的数据。 2、索引的优点: (1)、创建唯一性索引,可以确保数据的唯一性; (2)、大大加快数据检索速度; (3)、加速表与表之间的连接; (4)、在查询过程中,使用优化隐藏器,提高系统性能。 3、索引的缺点: (1)、创建和维护索引需要耗费时间,随数据量增加而增加; (2)、索引占用物理空间; (3)、对表的数据进行增删改时,索引需要动态维护,降低了数据的维护速度。
18 2
|
17天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
84 1
|
24天前
|
SQL 关系型数据库 MySQL
Mysql中搭建主从复制原理和配置
主从复制在数据库管理中广泛应用,主要优点包括提高性能、实现高可用性、数据备份及灾难恢复。通过读写分离、从服务器接管、实时备份和地理分布等机制,有效增强系统的稳定性和数据安全性。主从复制涉及I/O线程和SQL线程,前者负责日志传输,后者负责日志应用,确保数据同步。配置过程中需开启二进制日志、设置唯一服务器ID,并创建复制用户,通过CHANGE MASTER TO命令配置从服务器连接主服务器,实现数据同步。实验部分展示了如何在两台CentOS 7服务器上配置MySQL 5.7主从复制,包括关闭防火墙、配置静态IP、设置域名解析、配置主从服务器、启动复制及验证同步效果。
Mysql中搭建主从复制原理和配置
|
11天前
|
存储 关系型数据库 数据库
Postgres数据库BRIN索引介绍
BRIN索引是PostgreSQL提供的一种高效、轻量级的索引类型,特别适用于大规模、顺序数据的范围查询。通过存储数据块的摘要信息,BRIN索引在降低存储和维护成本的同时,提供了良好的查询性能。然而,其适用场景有限,不适合随机数据分布或频繁更新的场景。在选择索引类型时,需根据数据特性和查询需求进行权衡。希望本文对你理解和使用PostgreSQL的BRIN索引有所帮助。
19 0
|
18天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
47 0
|
8天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
23 1
|
10天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
25 4
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引