MySQL之索引及其背后的数据结构

news2024/11/24 3:08:23

博客主页:系列专栏: MySQL
一句短话: 难在坚持,贵在坚持,成在坚持!

文章目录

  • 一. 索引的介绍
    • 1. 什么是索引
    • 2. 索引的使用
  • 二. 索引背后的数据结构
    • 1. 考虑使用哈希表
    • 2. 二叉搜索树
    • 3. N叉搜索树(B树, B+树)
    • 4. 注意事项

一. 索引的介绍

1. 什么是索引

索引 (Index) 是帮助MYSQL高效获取数据的数据结构, 是一种特殊的文件, 包含着对数据表里所有记录的引用指针; 可以对表中的一列或多列创建索引, 并指定索引的类型, 各类索引有各自的数据结构实现.

索引 (index) 其实好比书的目录, 用于加快查找的效率.

索引的作用

  • 数据库中的表、数据、索引之间的关系,类似于书架上的图书、书籍内容和书籍目录的关系。
  • 索引所起的作用类似书籍目录,可用于快速定位、检索数据。
  • 索引对于提高数据库的性能有很大的帮助。

使用场景:
要考虑对数据库表的某列或某几列创建索引,需要考虑以下几点:

  • 数据量较大,且经常对这些列进行条件查询。
  • 该数据库表的插入操作,及对这些列的修改操作频率较低。
  • 索引会占用额外的磁盘空间。

满足以上条件时,考虑对表中的这些字段创建索引,以提高查询效率。

反之,如果非条件查询列,或经常做插入、修改操作,或磁盘空间不足时,不考虑创建索引。

使用索引会提高空间的开销, 构造索引需要额外的硬盘空间来保存; 索引在提高找效率的同时也加剧了增删改的开销, 此时的增删改, 需要调整已经创建好的索引目录.

2. 索引的使用

创建主键约束(primary key)、唯一约束(unique)、外键约束(foreign key)时,会自动创建对应列的索引。

索引相关的操作使用index关键字.

  • 创建索引

对于非主键、非唯一约束、非外键的字段,可以创建普通索引

语法:

create index 自定义索引名 on 表名(字段名);

示例: 创建班级表中, name字段的索引.

-- 创建学生表
mysql> create table student (
    ->     id int primary key,
    ->     name varchar(20)
    -> );
Query OK, 0 rows affected (0.03 sec)
-- 给name列添加索引
mysql> create index idx_student_name on student(name);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

注意:

  1. 索引最好是在表创建之初就完成全部创建.

如果是在一个表中已经有很多条记录的基础上来创建索引, 这个操作是非常危险的, 这个时间段内就会开销大量的磁盘IO, 数据库就无法被正常使用, 如果数据量很大的话, 这个时间段是很长的, 也就是说, 数据库可能在较长一段时间内无法正常使用.

  1. 索引的存在是为了提高查询的速度, 但索引一定要创建在合适的列上才有意义.

比如, 如果上面的student表中再添加一个字段性别(sex), 给这个字段添加索引并不能提高查找速度, 因为记录中sex字段的值会有大量的重复数据.

  • 查看索引

语法:

show index from 表名;

示例:查看学生表已有的索引

img

mysql> show index from student;
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| student |          0 | PRIMARY          |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| student |          1 | idx_student_name |            1 | name        | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)
  • 删除索引

语法:

drop index 索引名 on 表名;

示例:删除班级表中name字段的索引

-- 删除索引
mysql> drop index idx_student_name on student;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
-- 查看剩下的索引
mysql> show index from student;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| student |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

注意:

同样的, 删除索引也可能会开销大量的磁盘IO, 也是比较危险的操作.

二. 索引背后的数据结构

1. 考虑使用哈希表

哈希表的查找效率为O(1)

考虑索引的底层实现是否可以使用哈希表,

哈希表查找数据的过程: 把key代入哈希函数, 计算得到下标, 再根据下标取到对应的链表, 再去遍历比较key是否相等.

上面的过程只能查一条记录, 而在数据库中很多情况下需要的是范围查询.

比如: 查找id<8并且>6的学生信息

select * from student where id < 8 and id > 6;

类似于这种简单或者更复杂的范围查询在哈希表中是无法实现的.

总结: 哈希表不适合做数据库的索引, 哈希表只能进行相等比较, 不能处理> >= < <= between and…这些范围查询.

2. 二叉搜索树

普通的二叉搜索树查找的时间复杂度, 一般情况下可以认为是O(logN), 考虑最坏的情况单枝树的情况下, 时间复杂度为O(N).

如果这个二叉搜索树比较平衡(AVL / 红黑树), 时间复杂可以达到O(logN).

二叉搜索树可以中序遍历(从起点到终点)进行范围查询, 但数据库索引并没有使用二叉搜索树来实现, 原因如下:
首先, 数据库中的比较是要读硬盘(磁盘IO)的, 读硬盘的次数太多会拖慢查找速度.

二叉(只有左右两个节点, 一个节点中放置一条记录)意味着当元素个数很多的时候, 树的高度就会比较高, 树的高度决定了了查询的时候元素比较的次数, 这样的话数据量大的时候查询还是会慢.

3. N叉搜索树(B树, B+树)

N叉搜索树: 每个节点上有多个值, 同时又有多个分支.

N叉搜索树中其中一种典型的实现就是B树.

img

使用B树实现索引有如下特点:

不再是二叉搜索,而是N叉搜索,树的高度会降低,查询快

  • 叶子节点,非叶子节点,都可以存储数据,且可以存储多个数据
  • 通过中序遍历,可以访问树上所有节点

如果B树被作为实现索引的数据结构被创造出来,是因为它能够完美的利用“局部性原理”,其设计逻辑是这样的:

  • 内存读写快,磁盘读写慢,而且慢很多
  • 磁盘预读:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载一些看起来是冗余的数据,如果未来要读取的数据就在这一页中,可以避免未来的磁盘读写,提高效率(通常,一页数据是4K)
  • 局部性原理:软件设计要尽量遵循“数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO效能

这里的B树一个节点中有多条记录, 相对于上面的二叉搜索树, 树的高度会降低很多, 读写硬盘的次数减少了, 但总体的比较次数相差不多(一个节点上可能需要多次比较).

而最适合做数据库索引的结构是B+树, B+树在B树的基础上进行了进一步的改进, B+树是为索引这个场景量身定做的数据结构.

img

  1. B+树也是一个N叉搜索树, 每个节点上可能包含N个key, N个key划分出N个区间; 最后一个key就相当于最大值了.
  2. 父元素的key会在子元素中重复出现, 这样的重复出现会让叶子节点包含了所有数据的全集, 非叶子节点的所有值都会在叶子节点中体现出来.
  3. 会把叶子节点, 用类似于链表的方式首尾巴相连.

使用B+树实现索引有如下特点:

  • 作为一个N叉搜索树, 层级(树的高度)小, 比较的时候, 硬盘IO的次数就少.
  • 叶子之间,增加了链表,获取所有节点,不再需要中序遍历,使用链表的next节点就可以快速访问到
  • 范围查找方面,当定位min与max之后,中间叶子节点,就是结果集,不用中序回溯(范围查询在SQL中用得很多,这是B+树比B树最大的优势)
  • 非叶子节点不再存储数据,数据只存储在同一层的叶子节点上,B+树从根到每一个节点的路径长度一样,也就是说, 不管查询的什么, 中间比较的次数都是差不多的, 查询操作比较均衡, 而B树不是这样
  • 叶子节点存储实际记录行,记录行相对比较紧密的存储,适合大数据量磁盘存储;非叶子节点存储记录的id,不存储实际记录,这就意味着非叶子节点占用的空间是大大降低的,适合用内存存储, 更进一步降低了硬盘IO.img

4. 注意事项

使用索引提高查询速度, 本质上是在减少硬盘IO的次数

MySQL中对于带有主键的表, 就是按照主键索引的B+树来组织的.

如果表中不止以有主键索引, 还有别的非主键列, 也有索引; 对于非主键列会构造另一个B+树, 树中非叶子节点存储的都是这一列里面的key(比如一堆学生的姓名), 到了叶子节点这一层, 存储的不是完整的数据行, 存的只是id(主键列);

所以, 当使用非主键列的索引进行查询时, 需要先查一遍索引列的B+树, 找到对应的主键列, 再查一遍主键列的B+树(回表), 查询过到对应的记录.

上面所说的数据库索引的实现用的是B+树这个结构, 要注意这里只是针对MySQL的InnoDB(最主流使用的一种存储引擎)这个数据引擎里面所使用的数据结构, 不同的数据库, 不同的引擎, 里面的存储数据的结构还可能存在差异.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[激光原理与应用-39]:《光电检测技术-6》- 光干涉的原理与基础

目录 第1章 概述 1.1 什么是光干涉 1.2 产生干涉的必要条件 1.3 非相干光 - 自发辐射无法产生干涉 1.4 相干光 - 受激辐射 1.5 时间相干性 1.6 空间相干性 它山之石 第1章 概述 1.1 什么是光干涉 它是指因两束光波相遇而引起光的强度重新分布的现象。 指两列或两列以上…

Verilog入门学习笔记:Verilog基础语法梳理

无论是学IC设计还是FPGA开发&#xff0c;Verilog都是最基本、最重要的必备技能。但任何一门编程语言的掌握都需要长期学习。并不是简简单单的随便读几本书&#xff0c;随便动动脑筋那么简单。Verilog是一门基于硬件的独特语言&#xff0c;由于它最终所实现的数字电路&#xff0…

基于AVDTP信令分析蓝牙音频启动流程

前言 公司项目edifier那边需要在原来音频SBC,AAC基础上增加LHDC5.0编码&#xff0c;在打通lhdc协议栈之前&#xff0c;学习记录一番AVDTP音频服务流程。 一、AVDTP音频流基础知识 分析音频流程首先应具备的最简单基础概念知识&#xff1a;AVDTP信令signal&#xff0c;流端点se…

【JVM】垃圾回收机制详解(GC)

目录一.GC的作用区域二.关于对象是否可回收1.可达性分析算法和引用计数算法2.四种引用类型三.垃圾收集算法1.标记-清除算法2.复制算法3.标记-整理算法4.分代收集算法四.轻GC(Minor GC)和重GC(Full GC)一.GC的作用区域 可以看jvm详解之后&#xff0c;再来理解这篇文章更好 堆和…

[附源码]计算机毕业设计农村人居环境治理监管系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

ASP.NET Core 3.1系列(18)——EFCore中执行原生SQL语句

1、前言 前一篇博客介绍了EFCore中常见的一些查询操作&#xff0c;使用Linq或Lambda结合实体类的操作相当方便。但在某些特殊情况下&#xff0c;我们仍旧需要使用原生SQL来获取数据。好在EFCore中提供了完整的方法支持原生SQL&#xff0c;下面开始介绍。 2、构建测试数据库 …

Radare2 框架介绍及使用

Radare2 框架介绍及使用 欢迎入群交流 radare2 这是整个框架的核心工具&#xff0c;它具有debugger和Hexeditor的核心功能&#xff0c;使您能够像打开普通的文件一样&#xff0c;打开许多输入/输出源&#xff0c;包括磁盘、网络连接、内核驱动和处于调试中的进程等。 它实现了…

旧版本金庸群侠传3D新Unity重置修复版入门-lua”脚本“

金庸3DUnity重置入门系列文章 金庸3dUnity重置入门 - lua 语法 金庸3dUnity重置入门 - UniTask插件 金庸3dUnity重置入门 - Cinemachine 动画 金庸3dUnity重置入门 - 大世界实现方案 金庸3dUnity重置入门 - 素材极限压缩 (部分可能放到付费博客&#xff09; 2022年底~20…

Apifox和Eolink两个测试工具谁最实用?

目前行业内有 postman、jmeter 为代表开源 Api 工具派系&#xff0c;我想对大家对这两个词并不陌生。虽然它们能解决基本的接口测试&#xff0c;但是无法解决接口链路上的所有问题&#xff0c;一个工具难以支持整个过程。在国内&#xff0c;我们可以看到有国产 API 管理工具&am…

Spring Cloud 微服务讲义

Spring Cloud 微服务讲义第一部分 微服务架构第 1 节 互联网应用架构演进第 2 节 微服务架构体现的思想及优缺点第 3 节 微服务架构中的核心概念第二部分 Spring Cloud 综述第 1 节 Spring Cloud 是什么第 2 节 Spring Cloud 解决什么问题第 3 节 Spring Cloud 架构3.1 Spring …

CCES软件做开发,如果仿真器连不进目标板怎么解决?(Failed to connect to processor)

ADI的DSP调试&#xff0c;我在Visual DSP软件下写过一个详细的帖子&#xff0c;来说明仿真器如果连不进目标板&#xff0c;可能存在的几种问题以及解决办法&#xff0c;现在在CCES软件下遇到了同样的问题&#xff0c;所以准备再写一个帖子说明一下。 我们都知道ADI的DSP&#…

智慧工地管理平台系统厂家哪家强|喜讯科技

喜讯科技针对施工现场涉及面广&#xff0c;多种元素交叉&#xff0c;状况较为复杂&#xff0c;如人员出入、机械运行、物料运输等工程项目管理在一定程度上存在着决策层看不清、管理层管不住、执行层做不好的问题。 围绕施工现场管理&#xff0c;构建全方位的智能监控防范体系弥…

Redis——Linux下安装以及命令操作

一、概述 redis是什么&#xff1f; Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。 是一款高性能的NOSQL系列的非关系型…

每日一题:冒泡排序

每日一题&#xff1a;冒泡排序每日一题:冒泡排序第一种写法&#xff1a;第二种写法&#xff1a;每日一题:冒泡排序 冒泡排序是八大排序中较为简单的一种&#xff0c;具体详细可见&#xff1a;冒泡排序_百度百科 (baidu.com) 我们重点来看冒泡排序的步骤&#xff1a; 冒泡排序…

程序员如何写游戏搞钱?

ConcernedApe&#xff0c;一个叫做Eric Barone的程序员研发了一款叫做星露谷的小游戏&#xff0c;以乡村经营生活为核心&#xff0c;打造了一个虚拟的小世界&#xff0c;在这个小世界&#xff0c;你可以种植农作物&#xff0c;经营农场并挖矿钓鱼。 其中钓鱼的玩法是十分新颖的…

Git常见问题

1.拉取的项目很大&#xff0c;如1G以上&#xff0c;此时报错early EOF 具体报错如下&#xff1a; Cloning into csp-doc... remote: Counting objects: 6061, done. remote: Compressing objects: 100% (4777/4777), done. error: RPC failed; curl 18 transfer closed with …

Spring - FactoryBean扩展实战_MyBatis-Spring 启动过程源码解读

文章目录PrePreMyBatis-Spring 组件扩展点org.mybatis.spring.SqlSessionFactoryBeanInitializingBean扩展接口 afterPropertiesSetFactoryBean 扩展接口 getObjectApplicationListener扩展接口 onApplicationEvent扩展点org.mybatis.spring.mapper.MapperFactoryBeanSqlSessio…

【Linux基本命令归纳整理】

Linux 是一套免费使用和自由传播的类 Unix 操作系统&#xff0c;是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。严格来讲&#xff0c;Linux 这个词本身只表示 Linux 内核&#xff0c;但实际上人们已经习惯了用 Linux 来形容整个基于 Linux 内核&…

Day40——Dp专题

文章目录三、01背包8.分割等和子集9.最后一块石头的重量 II10.目标和11. 一和零三、01背包 8.分割等和子集 题目链接&#xff1a;416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;我们构造两个子集使得两个子集的和相等&#xff0c;其实就是让我…

JavaScript:初始JS 以及 基础语法

前端三件套&#xff1a; HTML: 生成网页控件 例如&#xff1a;生成 文本框 多选框 下拉列表 等 (人的身体) CSS: 修饰网页上的控件 例如&#xff1a;修饰文本框为圆形 &#xff08;人的衣服&#xff09; JavaSript: 在这些控件上添加逻辑 例如&#xff1a;获取文本框的值 然…