MySQL索引详解

news2024/11/22 14:56:55

目录

1、为什么要有索引?

2、预备知识

3、为何IO交互要是 Page?

4、如何理解Page以及索引理解

5、索引操作

<1> 创建主键索引

<2> 创建唯一索引

<3> 普通索引的创建

<4> 全文索引的创建

<5> 查询索引

<5> 删除索引

<6> 索引创建原则


1、为什么要有索引?

索引:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调 sql ,只要执行正确的 create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO 。所以它的价值,在于提高一个海量数据的检索速度
常见索引分为:
  • 主键索引(primary key)
  • 唯一索引(unique)
  • 普通索引(index)
  • 全文索引(fulltext)--解决中子文索引问题。

2、预备知识

MySQL 与磁盘交互基本单位

MySQL 作为一款应用软件,可以想象成一种特殊的文件系统。它有着更高的 IO 场景,所以,为了提高基本的 IO 效率, MySQL 进行 IO 的基本单位是 16KB。

磁盘硬件设备的基本单位是 512 字节,而 MySQL InnoDB引擎 使用 16KB 进行IO交互。即MySQL 和磁盘进行数据交互的基本单位是 16KB 。这个基本数据单元,在 MySQL 这里叫做page。

总结:
  • MySQL 中的数据文件,是以page为单位保存在磁盘当中的
  • MySQL CURD 操作,都需要通过计算,找到对应的插入位置,或者找到对应要修改或者查询的数据
  • 而只要涉及计算,就需要CPU参与,而为了便于CPU参与,一定要能够先将数据移动到内存当中
  • 所以在特定时间内,数据一定是磁盘中有,内存中也有。后续操作完内存数据之后,以特定的刷新策略,刷新 到磁盘。而这时,就涉及到磁盘和内存的数据交互,也就是IO了。而此时IO的基本单位就是Page
  • 为了更好的进行上面的操作, MySQL 服务器在内存中运行的时候,在服务器内部,就申请了被称为 Buffer Pool 的的大内存空间,来进行各种缓存。其实就是很大的内存空间,来和磁盘数据进行IO交互
  • 如何能有更高的效率,一定要尽可能的减少系统和磁盘IO的次数

3、为何IO交互要是 Page?

如下面的 5 条记录,如果 MySQL 要查找 id=2 的记录,第一次加载 id=1 ,第二次加载 id=2 ,一次一条记录,那么就需要 2 IO 。 如果要找id=5 ,那么就需要 5 IO 。 但如果这5 ( 或者更多 ) 都被保存在一个 Page (16KB ,能保存很多记录 ), 那么第一次 IO 查找 id=2 的时候,整个 Page 会被 加载到MySQL Buffer Pool 中,这里完成了一次 IO 。但是往后如果在查找 id=1,3,4,5 等,完全不需要进行 IO 了,而是直 接在内存中进行了。所以,就在单Page 里面,大大减少了 IO 的次数。
怎么保证,用户一定下次找的数据,就在这个 Page 里面?不能严格保证,但是有很大概率,因为有局部性原理。 往往IO 效率低下的最主要矛盾不是IO单次数据量的大小,而是IO的次数。
//创建测试表格
mysql> create table if not exists user (
    -> id int primary key, 
    -> age int not null,
    -> name varchar(16) not null
    -> );

//我们并没有按照主键大小顺序插入
mysql> insert into user (id, age, name) values(3, 18, '小明');
mysql> insert into user (id, age, name) values(5, 17, '小花');
mysql> insert into user (id, age, name) values(1, 20, '张三');
mysql> insert into user (id, age, name) values(4, 23, '李四');
mysql> insert into user (id, age, name) values(2, 23, '王五');

我们发现竟然默认是有序的,那么是谁干的呢?不难想象当然是主键干的,其实当我们建表的时候添加上主键默认就是主键索引。而主键之所以要这样干其实是为了方便维护page。 

4、如何理解Page以及索引理解

理解单个Page

MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要先描述,在组织 ,我们目前可以简单理解成一个个独立文件是由一个或者多个Page构成的。 

                                      

不同的 Page ,在 MySQL 中,都是 16KB ,使用 prev next 构成双向链表因为有主键的问题, MySQL 会默认按照主键给我们的数据进行排序,从上面的 Page 内数据记录可以看出,数据是有 序且彼此关联的。
为什么数据库在插入数据时要对其进行排序呢?我们按正常顺序插入数据不是也挺好的吗?
插入数据时排序的目的,就是优化查询的效率。页内部存放数据的模块,实质上也是一个链表的结构,链表的特点也就是增删快,查询修改慢,所以优化查询的效率是必须的。 正是因为有序,在查找的时候,从头到后都是有效查找,没有任何一个查找是浪费的,而且如果运气好,是可以提前结束查找过程的。
如何提高在一个页内搜索的效率呢?
我们在看 书的时候,如果我们要看某个章节 ,找到该章节有两种做法
  • 从头逐页的向后翻,直到找到目标内容
  • 通过书提供的目录,找到该章节所在的页数
  • 本质上,书中的目录,是多花了纸张的,但是却提高了效率
  • 所以,目录,是一种空间换时间的做法

同样我们页内提高效率也是通过添加目录的方式来提高页内查找的效率。

理解多个Page

 刚刚我们已经解决了页内的效率问题,那么多页又怎么办呢?如果这个链表很长难道要从头开始遍历吗?

当然不是,我们解决多页效率问题和解决页内方法相同同样也给添加上目录,如图。

  •  相信学过B+树的朋友们已经看出来了,其实这种结构就是B+树。至此我们已经构建出了主键索引
  • 随便找一个id我们都可以快速的查找到。如找id为14的数据首先会将14和1、11比较,比11大继续和11、16比较在二者之间此时我们就能锁定14所在的页,在进行页内查找就可以了。我们发现,现在查找的Page数一定减少了,也就意味着IO次数减少了,那么效率也就提高了

那B+树在哪里呢?

  • 在磁盘上有完整的B+树和数据
  • 在内存中有局部高频被访问的B+核心Page
  • mysql查找一定会伴生着mysql根据B+进行Page的换入换出

 总结:

  • Page分为目录页和数据页。目录页只放各个下级Page的最小键值。
  • 查找的时候,自定向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数

 InnoDB 在建立索引结构来管理数据的时候,其他数据结构为何不行?

  • 链表?线性遍历
  • 二叉搜索树?退化问题,可能退化成为线性结构
  • AVL &&红黑树?虽然是平衡或者近似平衡,但是毕竟是二叉结构,相比较多阶B+,意味着树整体过高,大家都是自顶向下找,层高越低,意味着系统与硬盘更少的IO Page交互。虽然你很秀,但是有更秀的。
  • Hash?官方的索引实现方式中, MySQL 是支持HASH的,不过 InnoDB MyISAM 并不支持。Hash跟进其算法特征,决定了虽然有时候也很快(O(1)),不过,在面对范围查找就明显不行

B树 VS B+树

如图:

 区别:

  • B 树节点,既有数据,又有 Page 指针,而 B+ ,只有叶子节点有数据,其他目录页,只有键值和 Page 指针
  • B+叶子节点,全部相连,而 B 没有
为何选择B+
  • 节点不存储 data ,这样一个节点就可以存储更多的 key 。可以使得树更矮,所以 IO 操作次数更少。
  • 叶子节点相连,更便于进行范围查找

5、索引操作

<1> 创建主键索引

  • 方式一
在创建表的时候,直接在字段名后指定 primary key
create table user1(id int primary key, name varchar(30));
  • 方式二
在创建表的最后,指定某列或某几列为主键索引
create table user2(id int, name varchar(30), primary key(id));
  • 方式三
create table user3(id int, name varchar(30));
创建表以后再添加主键
alter table user3 add primary key(id);
主键索引的特点:
  • 一个表中,最多有一个主键索引,当然可以使符合主键
  • 主键索引的效率高(主键不可重复)
  • 创建主键索引的列,它的值不能为null,且不能重复
  • 主键索引的列基本上是int

<2> 创建唯一索引

  • 方式一
在表定义时,在某列后直接指定 unique 唯一属性。
create table user1(id int primary key, name varchar(30) unique);
  • 方式二
创建表时,在表的后面指定某列或某几列为 unique
create table user2(id int primary key, name varchar(30), unique(name));
  • 方式三
create table user3(id int primary key, name varchar(30)
创建表以后再添加唯一键
alter table user3 add unique(name);
唯一索引的特点:
  • 一个表中,可以有多个唯一索引
  • 查询效率高
  • 如果在某一列建立唯一索引,必须保证这列不能有重复数据
  • 如果一个唯一索引上指定not null,等价于主键索引

<3> 普通索引的创建

  • 方式一
create table user1(
id int primary key,
name varchar(20),
email varchar(30),
index(name) 在表的定义最后,指定某列为索引
);
  • 方式二
create table user9(id int primary key, name varchar(20), email varchar(30));
alter table user9 add index(name); 创建完表以后指定某列为普通索引
  • 方式三
create table user10(id int primary key, name varchar(20), email varchar(30));
创建一个索引名为 idx_name 的索引
create index idx_name on user10(name);
普通索引的特点:
  • 一个表中可以有多个普通索引,普通索引在实际开发中用的比较多
  • 如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引

<4> 全文索引的创建

当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。 MySQL 提供全文索引机制,但是有要求,要求 表的存储引擎必须是MyISAM ,而且默认的全文索引支持英文,不支持中文。如果对中文进行全文检索,可以使用 sphinx的中文版 (coreseek)
create table  articles (
id int unsigned auto_increment not null primary key,
title varchar(200),
body text,
fulltext(title,body)
)engine=MyISAM;

<5> 查询索引

  • 方法一
show keys from 表名;
  • 方法二
第二种方法 : show index from 表名;
                          
  • 方法三
desc 表名;

<5> 删除索引

  • 第一种方法:  删除主键索引: alter table 表名 drop primary key
  • 第二种方法:  其他索引的删除: alter table 表名 drop index 索引名; 索引名就是 show keys from 表名中的
    Key_name 字段 
  • 第三种方法方法: drop index 索引名 on 表名mysql> drop index name on user8

<6> 索引创建原则

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

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

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

相关文章

Python图像识别实战(五):卷积神经网络CNN模型图像二分类预测结果评价(附源码和实现效果)

前面我介绍了可视化的一些方法以及机器学习在预测方面的应用&#xff0c;分为分类问题&#xff08;预测值是离散型&#xff09;和回归问题&#xff08;预测值是连续型&#xff09;&#xff08;具体见之前的文章&#xff09;。 从本期开始&#xff0c;我将做一个关于图像识别的…

BOOT进程控制模式与故障排错

1. BOOT reboot and shutdown—使用systemctl 命令。 systemctl poweroff–关机 systemctl reboot --重启 systemctl halt 禁用CPU 在7版本中使用systemctl 工具。 选择systemd target graphical.target 桌面图形模式 multi-user.target 多用户模式–命令行 rescue.target 救援…

Linux驱动开发基础__总线设备驱动模型

目录 1 驱动编写的三种方法 1.1 传统写法 1.2 总线设备驱动模型 1.3 设备树 2 在 Linux 中实现“分离”&#xff1a;Bus/Dev/Drv 模型 3 匹配原则 4 函数调用关系 1 驱动编写的三种方法 1.1 传统写法 1.2 总线设备驱动模型 引入platform_device、platform_driver&…

二叉数题型2

目录 二叉搜索树的众数 二叉树的最近公共祖先 修剪二叉树 二叉搜索树的众数 问题描述&#xff1a; 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#…

PROJ 9.1.1源码下载编译(Win10+VS2022)

目录PROJ什么是PROJPROJ下载方式资源结构编译PROJ打包编译成功的库PROJ 什么是PROJ Proj是一个免费的GIS工具。 它专注于地图投影的表达&#xff0c;以及转换。采用一种非常简单明了的投影表达PROJ&#xff0c;比其它的投影定义简单&#xff0c;但很明显。很容易就能看到各种…

无人机倾斜摄影测量技术的优势有哪些?

传统的地理信息获取工作一般是通过人工测量的方式进行&#xff0c;但这样的测量方式具有工作强度大、成本高等问题。随着现代科技的不断发展&#xff0c;测绘行业对地理信息数据的准确性、时效性要求也越来越高&#xff0c;人工成本和时间成本也为行业带来了巨大的压力。因此&a…

GIT回退到指定版本的两种方法(reset/revert)

实现多人合作程序开发的过程中&#xff0c;我们有时会出现错误提交的情况&#xff0c;此时我们希望能撤销提交操作&#xff0c;让程序回到提交前的样子&#xff0c;本文总结了两种解决方法&#xff1a;reset、revert。 命令特点reset该命令会强行覆盖当前版本和要回退的版本之…

ArcGIS基础实验操作100例--实验15设置字段属性域

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验15 设置字段属性域 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&a…

如何用Sonic云真机打王者

使用Sonic进行跨网段部署&#xff0c;助力海外业务的公司进行专项检测。提供定时任务充分利用无人值守时间回归UI测试&#xff0c;省时省力。自研随机事件测试与UI遍历测试&#xff0c;支持打通Jenkins的DevOps流程&#xff0c;Sonic提供图像识别&#xff0c;后续还会添加poco控…

ECS-弹性容器服务 - Part 2

68-ECS-弹性容器服务 - Part 2 Hello大家好&#xff0c;我们今天继续ECS的内容。 Service load balancing 之前的课时讨论过&#xff0c;在ECS集群上创建的ECS服务支持AWS负载均衡器&#xff0c;而应用程序负载均衡器和ECS服务通常是一个很好的搭配&#xff0c;因为应用程序负…

Docker 基础概念介绍

一 什么是 docker &#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;…

【nowcoder】笔试强训Day13

目录 一、选择题 二、编程题 2.1参数解析 2.2跳石板 一、选择题 1.一个关系数据库文件中的各条记录 &#xff08;&#xff09; 。 A. 前后顺序不能任意颠倒&#xff0c;一定要按照输入的顺序排列 B. 前后顺序可以任意颠倒&#xff0c;不影响库中的数据关系 C. 前后顺序…

前端面试题之计算机网络篇--HTTP协议

HTTP协议 1. GET和POST的请求的区别 GET和POST方法 GET和POST方法都是HTTP中的方法 什么是 HTTP&#xff1f; 超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff0c;缩写 HTTP&#xff09;旨在启用客户端和服务器之间的通信。 HTTP 充当客户端和服务器之间的…

Android进阶——Javac编译解析

Javac编译器 1.Javac的源码与调试 Javac的源码下载地址&#xff1a;Javac的源码下载地址&#xff0c;在Myeclipse中新建项目Compiler_javac&#xff0c;把源码复制到项目中。 Javac的源码目录&#xff1a; 从Sun Javac的代码来看&#xff0c;编译过程大致可以分为3个过程&…

测试工程师正遭「革命」 AI将改写测试模式

文章目录❤️‍&#x1f525; 软件测试的现状❣️ 功能测试的短板❣️ 过于的依赖工具❤️‍&#x1f525; 测试行业的两极分化❤️‍&#x1f525; 纯功能测试人员应该如何破局❣️ 龙测 AI TestOps 云平台❣️ AI TestOps 亮相 TICA❣️ AI TestOps 所实现的混合模型解决方案…

相关系数(皮尔逊pearson相关系数和斯皮尔曼spearman等级相关系数)

目录 总体皮尔逊Person相关系数&#xff1a; 样本皮尔逊Person相关系数&#xff1a; 两点总结&#xff1a; 假设检验&#xff1a;&#xff08;可结合概率论课本假设检验部分&#xff09; 皮尔逊相关系数假设检验&#xff1a; 更好的方法&#xff1a;p值判断方法 皮尔逊相…

lua调用c动态库实例

简介 Lua 是一种轻量小巧的脚本语言&#xff0c;用标准C语言编写并以源代码形式开放&#xff0c; 其设计目的是为了嵌入应用程序中&#xff0c;从而为应用程序提供灵活的扩展和定制功能。 特点 轻量级: 它用标准C语言编写并以源代码形式开放&#xff0c;编译后仅仅一百余K&a…

STM32/51单片机实训day4——RFID数据读取|RC522|串口数据收发、可模拟RFID (三) 仿真

目录 1 任务指导 2 实验步骤 3 串口调试 4 USART配置 5 fputs函数重写 内 容&#xff1a;能够读取RFID卡S50的ID——编程实现串口数据收发 学 时&#xff1a;3学时 知识点&#xff1a;电路图设计、USART配置 重点&#xff1a; USART配置 难点&#xff1a;USART配置 时…

赶快升级吧!PHP8比PHP5快41倍,比PHP7快3倍

本文得出的结论&#xff0c;归结于仅运行纯CPU任务的脚本的基准测试结果&#xff0c;不需要I/O操作的任务&#xff0c;例如访问文件、网络或数据库连接。 这些是纯 CPU 基准测试。它们并未涵盖 PHP 性能的所有方面&#xff0c;并且它们可能无法代表实际情况。然而&#xff0c;结…

用Python标准库统计CSDN阅读量

urllib基础 一般做爬虫其实很少有推荐urllib的&#xff0c;但urllib乃是Python标准库成员&#xff0c;在要求比较简单的情况下&#xff0c;采用urllib还是比较方便的。 作为爬虫入门必学包&#xff0c;urllib最常用的函数一定是urllib.request中的urlopen。其返回对象是HTTPR…