【MySQL】索引是什么东东?

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

索引和数据位于存储引擎中,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.mzph.cn/news/9670.shtml

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

相关文章

ansible中run_once的详细介绍和使用说明

在Ansible中&#xff0c;run_once是一个用于控制任务在主机组中只执行一次的关键字参数。当我们在编写Ansible任务时&#xff0c;有时候我们希望某个任务只在主机组中的某个主机上执行一次&#xff0c;而不是在每个主机上都执行。 以下是run_once参数的详细说明和用法&#xf…

PostgreSQL--实现数据库备份恢复详细教学

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;RodmaChen PostgreSQL--实现数据库备份恢复详细教学 一. 数据库备份二. 数据库恢复三. 存留问题 数据库备份恢复功能是每个产品所需的&#xff0c;以下是简单的脚本案例&a…

3-Linux实操

Linux实践操作 开关机、重启、用户登陆注销关机&重启用户登陆和注销 用户管理添加用户修改用户密码删除用户查询用户信息切换用户查看当前用户用户组的添加和删除用户和组相关文件 实用指令指定运行级别init 命令帮助指令文件目录类时间日期类搜索查找类&#x1f50d;压缩和…

Java获取调用当前方法的方法名和行数(亲测可行)

有时候一个方法被很多方法调用了&#xff0c;但是在调试应用程序的时候&#xff0c;需要知道是哪个方法调用它的&#xff0c;方便定位bug问题。否者&#xff0c;比较难以理清和解决一些bug问题。 适用&#xff1a;任何适用java语言编程的地方&#xff0c;java后端和android端。…

随手笔记——3D−3D:ICP求解

随手笔记——3D−3D&#xff1a;ICP求解 使用 SVD 求解 ICP使用非线性优化来求解 ICP 原理参见 https://blog.csdn.net/jppdss/article/details/131919483 使用 SVD 求解 ICP 使用两幅 RGB-D 图像&#xff0c;通过特征匹配获取两组 3D 点&#xff0c;最后用 ICP 计算它们的位…

实用人工智能 2.0,在线“学习、探索和构建”ML 模型

人工智能爱好者过去需要在一个好的GPU上投资数千美元才能“动手”进行机器学习&#xff0c;但现在一个简单的网络浏览器就足够了。总部位于硅谷的非营利组织PracticalAI最近发布了“PracticalAI2.0”&#xff0c;该平台包括TensorFlow 2.0Keras中的说明性机器学习课程&#xff…

嵌入式管理程序

在功能强大的计算机中使用虚拟机管理程序的想法是众所周知的。它有利于同时使用多个操作系统&#xff0c;并提供了可以在其中部署未修改的旧版软件的虚拟化环境。虚拟机管理程序在现代嵌入式系统中也占有一席之地。本文考虑了嵌入式管理程序的特性&#xff0c;它可以提供的功能…

【计算机网络】2.1——物理层(编码波形、奈氏准则和香农公式计算)

物理层 基本概念 概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流 为数据链路层屏蔽了各种传输媒体的差异 数据链路层只需要考虑如何完成本层的协议和服务&#xff0c;而不必考虑网络具体的传输媒体是什么 物理层协议主要任务 机械特性 指明接口所…

计算机网络最基础知识介绍

OSI和TCP/IP是很基础但又非常重要的知识,很多知识点都是以它们为基础去串联的,作为底层,掌握得越透彻,理解上层时会越顺畅。今天这篇网络基础科普,就是根据OSI层级去逐一展开的。 01 计算机网络基础 01 计算机网络的分类 按照网络的作用范围:广域网(WAN)、城域网(MA…

23.7.26总结(博客项目)

接下来要完成&#xff1a; 从主页面点击进入时&#xff0c;通过作者id从数据库查找作者的nickname点击文章收藏&#xff08;需要有收藏列表&#xff09;首页还要加最新发布&#xff0c;点赞收藏最多作者名得改成文章作者&#xff08;通过user_id从user表中拿数据&#xff09;消…

uniapp:手写签名,多张图合成一张图

要实现的内容&#xff1a;手写签名&#xff0c;协议内容。点击提交后&#xff1a;生成1张图片&#xff0c;有协议内容和签署日期和签署人。 实现的效果图如下&#xff1a; 1、签名页面 <template><view class"index"><u-navbar title"电子协议…

Android播放多媒体文件——播放音频

以下内容摘自郭霖《第一行代码》第三版 播放音频 MediaPlayer类中常用的控制方法 方法名功能描述setDataSource()设置要播放的音频文件的位置prepare()在开始播放之前调用&#xff0c;以完成准备工作start()开始或继续播放音频pause()暂停播放音频reset()将MediaPlayer对象重…

4.11 break、continue、goto

4.11 break、continue、goto break在任何循环语句的主体部分&#xff0c;均可用break控制循环的流程。break用于强行退出循环&#xff0c;不执行循环中剩余的语句。&#xff08;break语句也在switch语句中使用&#xff09; package com.baidu.www.struct;public class BreakDem…

企业级PaaS低代码快开平台源码,基于 Salesforce Platform 的开源替代方案

PaaS低代码快开平台是一种快速开发应用系统的工具&#xff0c;用户通过少量代码甚至不写代码就可以快速构建出各种应用系统。 随着信息化技术的发展&#xff0c;企业对信息化开发的需求正在逐渐改变&#xff0c;传统的定制开发已经无法满足企业需求。低代码开发平台&#xff0…

三分钟带你了解音频转文字哪个好用

在数字世界的角落里&#xff0c;有一项神奇的技术——音频转文字。它隐藏着巨大的力量和惊人的能力。它如同一位神奇的文字解码师&#xff0c;能够将听觉的旋律转化为视觉的符号&#xff0c;让语言的美妙之音在屏幕上跃然纸上。接下来&#xff0c;让我带你进入这个充满奇迹的数…

AQS抽象同步队列核心原理

CLH自旋锁 JUC中显式锁基于AQS抽象队列同步器&#xff0c;而AQS是CLH锁的一个变种。队列头结点可以获得锁&#xff0c;其他节点排队等候。 在争夺锁激烈的情况下&#xff0c;为了减少CAS空自旋&#xff08;CAS需要CPU进行内部通信保证缓存一致性造成流量过大引起总线风暴&…

马上医疗项目介绍

“马上好医”项目白皮书 一、大型医疗挂号微服务“马上好医”医疗项目 “马上好医”即为网上医疗预约挂号系统&#xff0c;首先&#xff0c;由于互联网的发展&#xff0c;衍生出非常多的便民医疗服务的需求&#xff0c;而网上预约挂号则是其中一个便民需求&#xff0c;我们能…

基于Javaweb实现ATM机系统开发实战(十五)退卡和转账跳转实现

首先创建一个servlet接受和处理请求&#xff1a; package com.atm.servlet;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException;//用户退出 WebServlet("/logout") public class ExitServlet ex…

安全渗透初级知识总结

Day1&#xff1a; xss详解&#xff1a;web攻防之XSS攻击详解——XSS简介与类型 - 知乎 (zhihu.com) Cookie&#xff1a;身份验证 网页元素属性&#xff1a; id&#xff1a; class&#xff1a;样式名称 console.log(div_class);----打印标签 tabindex"0"---这是…

JavaScript逻辑运算符

not运算符&#xff08;!&#xff09; 反着来and运算符&#xff08;&&&#xff09; 全true才trueor运算符&#xff08;||&#xff09; 全false才false 举例 const hasDriversLicense true; const Drinking false;console.log(hasDriversLicense && Drinking…