【MySQL】索引是什么东东?

news2024/11/27 20:22:46

书中的目录,就是充当索引的角色,方便我们快速查找书中的内容,所以索引是以空间换时间的设计思想。

索引和数据位于存储引擎中,MySQL默认的存储引擎是InnoDB。

1 为什么MySQL采用B+树作为索引?

1.1 其他数据结构为什么不合适?

MySQL的数据是持久化的,即数据(索引+记录)保存在磁盘上,即使断电,数据也不会丢失。

因此,当我们通过索引查找某行数据的时候,实际上是:

  • 先从磁盘读取索引到内存
  • 通过索引从磁盘中找到某行数据读入到内存

查询过程中会发生多次磁盘IO,而磁盘非常非常非常慢,我们希望索引的数据结构能在尽可能少的磁盘的 I/O 操作中完成查询工作:

一次磁盘访问的代价大约是几十万条指令。这意味着为了节省一次磁盘访问,我们愿意进行大量的运算。《数据结构与算法设计——Java语言描述》

因此,适合MySQL索引的数据结构,应该满足:在尽可能少的磁盘IO操作中查询某个记录 / 执行范围查找

哈希?只适合等值查询,不适合范围查询。

二分查找?NoNoNo,插入和删除需要移动后续元素, O ( n ) O(n) O(n)的代价对磁盘来说太大太大。

二叉查找树?想法不错,但存在退化成链表的可能性。

平衡二叉查找树 / 红黑树 ?不管平衡二叉查找树还是红黑树,都会随着插入的元素增多,而导致树的高度变高,相较于多叉树,其需要访问的节点数更多,这就意味着磁盘 I/O 操作次数多,会影响整体数据查询的效率。对于磁盘来说,当树的节点数很大时, log ⁡ 2 N \log_2 N log2N远大于 log ⁡ M N \log_M N logMN,增加一个节点能够保存的索引数M,可以使树变得更矮胖。

B树?B 树的每一个节点最多可以包括 M − 1 M-1 M1个数据项和 M M M个子节点,超过这些要求的话就会分裂节点。B树的每个节点都包含数据(索引+记录),而用户的记录数据的大小很有可能远远超过了索引数据,在查询过程中会将无用的记录数据加载进内存,这就需要花费更多的磁盘 I/O 操作次数来读到有用的索引数据

B树参考:http://t.csdn.cn/kYHFi

1.2 B+树和B树的区别是什么?

是B树的变体,一棵M阶的B+树主要有这些特点:

  • 每个结点至多有 M M M个子女,每个节点里的数据按主键顺序存放
  • 非根节点关键值个数范围(?感觉按照USFCA的在线模拟,删除时并不一定要满足这个): M 2 ≤ k ≤ M − 1 \frac{M}{2} \le k \le M - 1 2MkM1
  • 相邻叶子节点是通过指针连起来的,并且通过关键字大小排序

因此,我们可以知道,二者的主要区别:

  1. B树内部节点保存数据,但B+树内部节点只保存索引。B+Tree 存储千万级的数据只需要 3-4 层高度就可以满足,千万级的表查询目标数据最多需要 3-4 次磁盘 I/O。对于单点查询来说,B 树进行单个索引查询时,最快可以在 O(1) 的时间代价内就查到,平均时间代价会比B树稍快一些,但是B树的查询波动会比较大,因为每个节点既存索引又存记录。
  2. B+树相邻的叶子节点通过链表指针连接,这种设计对于范围查找非常有帮助。比如查找12月1日至12月12日之间的订单,可以找到链表头,然后利用链表向后遍历,无需从根节点进行查询。而B树没有将叶子节点串联起来的结构,只能通过树的遍历完成范围查询,范围查询效率不如B+树。
  3. 查找过程中,B树在找到具体数值以后就结束,B+树需要通过索引找到叶子节点中的数据。
  4. B树中一个关键字出现且只出现在一个节点中,而B+树可以出现多次。即B+树有大量的冗余节点,删除时有时可以直接从叶结点中删除,甚至可以不动,或者很简单地修改非叶节点。

1.3 B+树的插入删除过程

原理说明:https://juejin.cn/post/6929833495082565646?searchId=202307261122017B0C2F66AFF8CF77995A

在线模拟:https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

插入:

  • 插入都是在叶节点进行,找到要插入的叶节点
  • 如果插入后,关键字数等于阶数M,分裂为两个 ⌈ m 2 ⌉ \lceil \frac{m}{2} \rceil 2m ⌊ m 2 ⌋ \lfloor \frac{m}{2} \rfloor 2m的节点,将第 ⌈ m 2 ⌉ \lceil \frac{m}{2} \rceil 2m个关键字上移到父节点。
  • 如果父节点包含的关键字数等于M,继续分裂。

删除:找到包含关键值的节点,如果关键值是当前节点的最大/最小值且存在于父节点中,则删除时需要相应调整父节点的值。

2 索引的分类分类

2.1 数据结构分类

从数据结构的角度来看,MySQL 常见索引有 B+Tree 索引、HASH 索引、Full-Text 索引。

img

2.2 物理存储分类

在创建表时,InnoDB存储引擎会根据不同的场景选择不同的列作为聚簇索引的索引列:

  • 有主键,使用主键
  • 没有主键,选择第一个NOT NULL和UNIQUE的列
  • 否则,自动生成隐式自增ID列

其他索引都属于辅助索引(Secondary Index),也叫做二级索引或者非聚簇索引

主键索引的 B+Tree 和二级索引的 B+Tree 区别如下:

  • 主键索引的 B+Tree 的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;
  • 二级索引的 B+Tree 的叶子节点存放的是主键值,而不是实际数据,检索时,如果查询的数据能在二级索引里查找到,就不需要回表,否则需要查找2个B+Tree

2.3 字段特性分类

从字段特性的角度来看,索引分为主键索引、唯一索引、普通索引、前缀索引。

  • 主键索引:建立在主键字段上的索引,通常在创建表的时候一起创建,一张表最多只有一个主键索引,索引列不允许有空值。
CREATE TABLE table_name  (
  ....
  PRIMARY KEY (index_column_1) USING BTREE
);
  • 唯一索引:建立在 UNIQUE 字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一,但是允许有空值。
CREATE TABLE table_name  (
  ....
  UNIQUE KEY(index_column_1,index_column_2,...) 
);
  • 普通索引:建立在普通字段上的索引,既不要求字段为主键,也不要求字段为 UNIQUE。
CREATE TABLE table_name  (
  ....
  INDEX(index_column_1,index_column_2,...) 
);

CREATE INDEX index_name
ON table_name(index_column_1,index_column_2,...); 
  • 前缀索引:前缀索引是指对字符类型字段前几个字符建立的索引,而不是在整个字段上建立的索引,前缀索引可以建立在字段类型为 char、 varchar、binary、varbinary 的列上。

2.4 按字段个数分类

从字段个数的角度来看,索引分为单列索引、联合索引。

联合索引具有最左匹配原则,即按照最左优先的方式进行索引的匹配。使用联合索引进行查询的时候,如果不遵循最左匹配原则,联合索引会失效。

比如(a, b, c)联合索引,是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序。所以,b 和 c 是全局无序,局部相对有序的,这样在没有遵循最左匹配原则的情况下,是无法利用到索引的。

Q1: select * from t_table where a > 1 and b = 2,联合索引(a, b)哪一个字段用到了联合索引的 B+Tree?

A1:只有a,进行索引扫描时,可以定位到符合a>1的第一条记录,然后沿着记录所在链表向后扫描

Q2:select * from t_table where a >= 1 and b = 2,联合索引(a, b)哪一个字段用到了联合索引的 B+Tree?

A2: a和b,可以定位到a=1、b=2的第一条记录,再向后扫描

实际开发工作中建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的 SQL 使用到。

3 什么时候需要/不需要创建索引?

由于索引占用空间,且创建、维护索引需要耗费时间,比如进行插入、更新、删除时,MySQL不仅要保存数据,还要维护索引,所以需要合理地选择使用索引。

什么时候适合使用索引?

  • 主键自动建立唯一索引

  • 字段唯一,比如UUID

  • 经常使用Where查询的字段,这样能够提高整个表的查询速度

  • 经常使用GROUP BY和ORDER BY的字段,这样查询时不用再做一次排序

  • 查询中排序的字段,排序的字段如果通过索引访问将大大提高排序速度

什么时候不需要创建索引?

  • where、group by、order by用不到的字段
  • 字段中存在大量重复数据,查询优化器发现某个值出现在表的数据行中的百分比(惯用的百分比界线是"30%")很高的时候,会忽略索引,进行全表扫描。
  • 表记录太少的时候,不需要创建索引

4 索引的失效与优化

  • like语句的前导模糊查询不能使用索引,like查询是以%开头,索引会失效

  • 负向条件查询不能使用索引,负向条件有:!=<>not innot existsnot like 等,优化案例:

    select * from doc where status != 1 and status != 2;  --优化前
    select * from doc where status in (0,3,4);            --优化后
    
  • 查询条件中带有or,除非所有的查询条件都建有索引

  • 如果列类型是字符串,那在查询条件中需要将数据用引号引用起来,否则索引失效,因为强制类型转换会导致全表扫描:

    select * from user where phone=13800001234;
    select * from user where phone='13800001234';
    
  • 索引列上参与计算,索引失效,尽量不要在索引列上做任何操作(计算、函数),例子:

    select * from doc where YEAR(create_time) <= '2016'; --优化前
    select * from doc where create_time <= '2016-01-01'; --优化后
    
  • 违背最左匹配原则,索引失效:

    select * from employees.titles where emp_no < 10010' and title='Senior Engineer'and from_date between '1986-01-01' and '1986-12-31';
    
     (empno、title、fromdate),emp_no 可以用到索引,而title 和 from_date 则使用不到索引
    
  • 如果MySQL估计全表扫描要比使用索引要快,索引失效

  • 如果明确知道只有一条结果返回,limit 1 能够提高效率

    select * from user where login_name=?;
    select * from user where login_name=? limit 1
    

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

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

相关文章

C语言每日一题:6.移除元素+合并两个有序数组。

第一题&#xff1a;移除元素 思路一&#xff1a; 一&#xff1a;暴力查找的方法&#xff1a; 1.找到对应val值的下标&#xff0c;返回数组的下标。 2.删除对应的下标&#xff0c;从前向后用后面覆盖前面。当后一个是数组最后一个数值是就赋值结束了&#xff08;注意数组越界的问…

【C++】开源:grpc远程过程调用(RPC)配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍grpc远程过程调用&#xff08;RPC&#xff09;配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜…

TikTok广告数据不好?收下这份常见问题自查手册!

你是一位跨境卖家吗&#xff1f;你是否在TikTok上投放过广告&#xff1f; 如果你的答案是肯定的&#xff0c;那么你可能遇到过一些困扰。比如&#xff0c;你的广告为什么不起量&#xff1f;为什么突然掉量了&#xff1f;为什么成本上升了&#xff1f;到底是哪里出了问题&#…

【MyBatis 学习三】子段不一致问题 多表查询 动态SQL

目录 一、解决Java实体类属性与数据库表字段不一致问题 &#x1f337;现象1&#xff1a;显示字段不对应&#xff1a;使用ResultType查询结果为null&#xff1b; &#x1f337;解决办法&#xff1a;字段不对应&#xff1a;使用ResultMap解决。 二、数据库的多表查询 &#…

【【51单片机的红外遥控】】

红外遥控&#xff0c;完全把控 红外遥控 利用红外光进行通信的设备&#xff0c;由红外LED将调制后的信号发出&#xff0c;再由专门的红外接收头进行解调输出 通信方式&#xff1a;单工 异步 红外LED波长&#xff1a;940nm 通信协议标准&#xff1a;NEC标准 用那种一体化红红外…

面试总结-Redis篇章(八)——Redis分布式锁

JAVA 面试总结-Redis分布式锁 模拟抢券场景 通过下面方法添加Synchronized锁来防止上述情况&#xff0c;如果上面是单体服务没有问题&#xff0c;但是如果项目是集群部署&#xff0c;会出现下面的问题&#xff0c;因为Synchronized是属于本地的锁端口8080和8081同时访问&#x…

抽象工厂模式——产品族的创建

1、简介 1.1、简介 抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比&#xff0c;抽象工厂模式中的具体工厂不只是创建一种产品&#xff0c;它负责创建一族产品 1.2、定义 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;提供…

【MySQL】SQL优化(九)

&#x1f697;MySQL学习第九站~ &#x1f6a9;本文已收录至专栏&#xff1a;MySQL通关路 ❤️文末附全文思维导图&#xff0c;感谢各位点赞收藏支持~ 一.插入数据 (1) 小规模数据 如果我们需要一次性往数据库表中插入多条记录: -- 例如我们需要插入大量数据 insert into t…

3.安装kubesphere

1.本地存储动态 PVC # 在所有节点安装 iSCSI 协议客户端&#xff08;OpenEBS 需要该协议提供存储支持&#xff09; yum install iscsi-initiator-utils -y # 设置开机启动 systemctl enable --now iscsid # 启动服务 systemctl start iscsid # 查看服务状态 systemctl status …

第三大的数

414、第三大的数 class Solution {public int thirdMax(int[] nums) {Arrays.sort(nums);int tempnums[0];int ansnums[0];int count 0;// if(nums.length<3){// return nums[nums.length-1];// }// else {for(int inums.length-1;i>0;i--){if (nums[i]>nums[i…

如何提高自己的软件测试水平之bug定位

同学们在面试投简历的时候会经常看到人家公司JD上写的要求之一&#xff0c;如下&#xff1a; 这句话大家不要以为随便写写的&#xff0c;在我工作的十几年过程中起码见过10个以上试用期没过的公司新人&#xff0c;公司在衡量一个测试工程师是否专业的标准之一就是&#xff1a;…

常用的数据结构 JAVA

目录 1、线性表2、栈&#xff1a;3、队列&#xff1a; 1、线性表 List<Object> narnat new ArrayList<>();ArrayList&#xff1a;动态数组 1、可以嵌套使用 2、add(x)添加元素x&#xff0c;remove(index)删除某个位置的元素 3、注意list是指向性的&#xff0c…

appium2.x 最新安装教程来了!不用再装 appium desktop 了!

前言 新的appium已经舍弃了appium-server&#xff0c;重新回归到只有命令行安装和启动appium服务。 本文是基于最新的appium2.x的安装教程。正想学习使用appium的不要错过。 1、安装最新版本的node.js 下载地址&#xff1a;https://nodejs.org/en&#xff0c;一路安装完成即…

SpringCloud学习笔记(五)ElasticSearch介绍

一、什么是ElasticSearch ElasticSearch是一款开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容ElasticSearch结合kibana、Logstash、Beats&#xff0c;也就是elastic stack&#xff08;ELK&#xff09;。被广泛应用在日志数据分析、实时监控等领域Elasti…

JAVA 正则表达式(heima)

JAVA 正则表达式&#xff08;heima&#xff09; public class RegexDemo01 {/** 正则表达式介绍&#xff1a;本质来说就是一个字符串&#xff0c;字符串中可以指定规则&#xff0c;来对其他字符串进行校验。* public boolean matches(String regex):根据传入的正则表达式&#…

Jmap-JVM(十六)

上篇文章说了ZGC是jdk11加入的&#xff0c;他是未来jvm垃圾收集器的奠定者&#xff0c;满足TB级别内存处理&#xff0c;STW时间保持在10ms以下。 Jmap 我们可以先通过jmap -histo 进程ip 来查看&#xff0c;但是这样看不太清晰&#xff0c;我们可以用这行命令生成一个文件&…

Vue中TodoList案例_动画

MyItem.vue : 主要是引入了import animate.css样式库&#xff0c;animate.css样式库配置见上一篇文章animate.css样式库&#xff0c;然后再li标签外套了transition标签&#xff0c;引用了name里面的名称是animate.css拿过来的&#xff0c;绑定了enter-active-class和leave-act…

前端实现导出excel表格

需求&#xff1a;实现勾选行导出为表格 一、安装插件 npm install --save file-saver xlsx运行项目报如下警告的话 运行npm install xlsx0.16.0 --save 来降低版本号&#xff08;最初我安装的版本号是0.18.16的版本&#xff09;再次运行项目就不会报如下警告了 二、新建一个ex…

嵌入式开发:单片机嵌入式Linux学习路径

SOC&#xff08;System on a Chip&#xff09;的本质区别在于架构和功能。低端SOC如基于Cortex-M架构的芯片&#xff0c;如STM32和NXP LPC1xxx系列&#xff0c;不具备MMU&#xff08;Memory Management Unit&#xff09;&#xff0c;适用于轻量级实时操作系统如uCOS和FreeRTOS。…

SOC FPGA之HPS模型设计(一)

目录 一、建立HPS硬件系统模型 1.1 GHRD 1.2 从0开始搭建HPS 1.2.1 FPGA Interfaces 1.2.1.1 General 1.2.1.2 AXI Bridge 1.2.1.3 FPGA-to-HPS SDRAM Interface 1.2.1.4 DMA Peripheral Request 1.2.1.5 Interrupts 1.2.1.6 EMAC ptp interface 1.2.2 Peripheral P…