热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

带你把MySQL索引吃透了

数据库|mysql教程mysql数据库-mysql教程支付宝网页支付源码,ubuntu脑图,tomcat显示默认主页,爬虫听书软件,php可以开发什么软件,天津关键词seo排名优化

数据库|mysql教程带你把MySQL索引吃透了
mysql
数据库-mysql教程
支付宝网页支付源码,ubuntu脑图,tomcat显示默认主页,爬虫听书软件,php可以开发什么软件,天津关键词seo排名优化lzw
mysql视频教学
电影商城源码,ubuntu密码忘了怎么,提供爬虫的工具,php离职,苹果seo线下lzw
MySQL,一个熟悉又陌生的名词,早在学习Javaweb的时候,我们就用到了MySQL数据库,在那个阶段,MySQL对我们来说似乎只是一个存储数据的好东西,存储时一股脑往里边塞,查询时也是盲目的全表查询(不带一点点优化)。
cesium 源码分析,vscode全选一个页面,ubuntu 硬件设备,tomcat怎么这么厉害,py爬虫培训,php 高级写法,简述你对seo的工作理解lzw
我们总是自欺欺人的觉得,我们通过其他方面来优化就好了阿,迟迟不愿面对MySQL高级,转而学习一些看似更为”高级”的东西,学Redis,来分担MySQL的压力,学MyCat等中间件,实现主从复制读写分离分库分表等等。(说的就是melo没错了)

到了准备面试的时候,发现面试题里边的MySQL一问三不知~

而自己学到的前沿中间件,问得几乎很少!!自己也只是会用,写简历时只能弱弱写上”了解”xxx中间件……

当然了,学习MySQL高级篇,不单单只是为了面试,实际的项目中,这一块的优化是十分重要的,体验过服务器宕机后,只能默默……..

从现在开始吧,此时上岸还来得及!!!趁着金三银四,补充补充MySQL高级篇的知识点,从如下几方面开启 MySQL高级篇之旅

带你把MySQL索引吃透了

建议通过侧边栏目录检索对您有帮助的部分,其中有emoji表情前缀属于重点部分,觉得对您有帮助的话,小编还会持续更进完善本篇文章和MySQL专栏。

索引定义

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。除了数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。如下面的示意图所示 :

带你把MySQL索引吃透了

左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找快速获取到相应数据。

索引优势加快查找排序的速率,降低数据库的IO成本以及CPU的消耗通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。索引劣势索引实际上也是一张表,保存了主键和索引字段,并指向实体类的记录,本身需要占用空间虽然增加了查询效率,但对于增删改,每次改动表,还需要更新一下索引 新增:自然需要在索引树中新增节点 删除:索引树中指向的记录可能会失效,意味着这棵索引树很多节点,都是失效的 改动:索引树中节点的指向可能需要改变

要知道,二叉查找树,此处一个节点只能存储一条数据,而一个节点呢,在MySQL里边又对应一个磁盘块,这样我们每次读取一个磁盘块,只能获取一条数据,效率特别的低,所以我们会想到采用B树这种结构来存储。

索引结构

索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,而且也不是所有的引擎都支持所有的索引类型。

BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引。HASH 索引:只有Memory引擎支持 , 使用场景简单 。R-tree 索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。Full-text (全文索引) :全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。

MyISAM、InnoDB、Memory三种存储引擎对各种索引类型的支持

索引

INNODB引擎

MYISAM引擎

MEMORY引擎

BTREE索引

支持

支持

支持

HASH 索引

不支持

不支持

支持

R-tree 索引

不支持

支持

不支持

Full-text

5.6版本之后支持

支持

不支持

我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。

BTREE

多路平衡搜索树,一棵m阶(m叉)BTREE满足:

每个节点最多m个孩子 孩子个数:ceil(m/2) 到 m 关键字个数:ceil(m/2)-1 到 m-1插入关键字案例

带你把MySQL索引吃透了

保证不破坏m阶B树的性质

由于3阶,最多只能2个节点,所以一开始26和30在一起,之后再来个85就要开始分裂了,30作为中间上位,26保持,85去到右边
即:中间位置上位,然后左边留在旧节点,右边去到新结点

带你把MySQL索引吃透了

上位后又需要分裂

带你把MySQL索引吃透了

相比优势

相比二叉搜索树,高度/深度更低,自然查询效率更高。

B+TREEB+树有两种类型的节点:内部结点(也称索引结点)和叶子结点。内部节点就是非叶子节点,内部节点不存储数据,只存储索引,数据都存储在叶子节点。内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序连接。父节点存有右孩子的第一个元素的索引

带你把MySQL索引吃透了

相比优势B+Tree的查询效率更加稳定。由于B+Tree只有叶子节点保存key信息,查询任何key都要从root走到叶子,所以更稳定。只需遍历叶子节点,就可以实现整棵树的遍历。MySQL中的B+Tree

MySql索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针(整体类似一个双向链表的结构),就形成了带有顺序指针的B+Tree,提高区间访问的性能。

细心的同学可以看出,这张图跟我们的二叉查找树简图的一个最大区别是什么?

二叉查找树过渡到B树,有一个显著的变化就是,一个节点可以存储多个数据了,相当于一个磁盘块里边可以存储多个数据,大大减少了我们的 IO次数!!

MySQL中的 B+Tree 索引结构示意图:

带你把MySQL索引吃透了

二叉查找树简图:

带你把MySQL索引吃透了

索引原理BTree索引:初始化介绍

浅蓝色的称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示)
如磁盘块1包含数据项17和35,包含指针P1、P2、P3,
P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。

真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。`非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。`查找过程

如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO。在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中通过二分查找搜索到29,结束查询,总计三次IO。

真实的情况是,3层的B+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

索引分类

在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB使用了B+树索引模型,所以数据都是存储在B+树中的。

每一个索引在InnoDB里面对应一棵B+树。
假设,我们有一个主键列为ID的表,表中有字段k,并且在k上有索引。
这个表的建表语句是:

mysql> create table T( id int primary key, k int not null, name varchar(16), index (k))engine=InnoDB;

表中R1~R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6),两棵树的示例示意图如下:

带你把MySQL索引吃透了

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。

主键索引

数据表的主键列使用的就是主键索引,且会默认创建,这也是为什么,我们还没学索引的时候,老师经常跟我们说根据主键查会快一点,原来主键本身就建好了索引。
主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。

辅助索引

辅助索引的叶子节点内容是主键的值。在InnoDB里,辅助索引也被称为二级索引(secondary index)。

如下图:

主键索引存放了整行数据辅助索引只存放了自己本身,以及id主键用于回表查询

带你把MySQL索引吃透了

根据上面的索引结构,我们来讨论一个问题:基于主键索引和辅助索引的查询有什么区别?

如果语句是select * from T where ID=500,即主键查询方式,则只需要搜索ID这棵B+树;如果语句是select * from T where k=5,即普通索引查询方式,则需要先搜索k索引树,得到ID的值为500,再到ID索引树搜索一次。这个过程称为回表

也就是说,基于辅助索引的查询需要多扫描一棵索引树。因此,我们在应用中应当尽量使用主键查询。

除非说,我们所要查询的数据,刚好就是我们索引树上存在的,此时我们称之为覆盖索引–即索引列中包含了我们要查询的所有数据。

同时,二级索引又分为了如下几种(先简单略过即可,后续我们再慢慢了解):

唯一索引(Unique Key) :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL,一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。普通索引(Index)普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。前缀索引(Prefix) :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。全文索引(Full Text) :全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引,5.6 之后 InnoDB 也支持了全文索引扩展–索引下推

所谓下推,顾名思义,其实是推迟我们的回表操作,MySQL不会轻而易举让我们去回表,因为很浪费。什么意思呢?来看下边这个例子。

我们建立了一个复合索引(name,status,address),索引中也是按这个字段来存储的,类似图中这样:

复合索引树(只存储索引列和主键用于回表)

name

status

address

id(主键)

小米1

0

1

1

小米2

1

1

2

我们执行这样一条语句:

SELECT name FROM tb_seller WHERE name like '小米%' and status ='1' ;

首先我们在复合索引树上,找到了第一个以小米开头的name — 小米1此时我们不着急回表(回到主键索引树搜索的过程,我们称为回表),而是先在复合索引树判断status是否=1,此时status=0,我们直接就不回表了,直接继续找下一个以小米开头的name找到第二个– 小米2,判断status=1,则根据id=2去主键索引树上找,得到所有的数据最左前缀原则

所谓最左前缀,可以想象成一个爬楼梯的过程,假设我们有一个复合索引:name,status,address,那这个楼梯由低到高依次顺序是:name,status,address,最左前缀,要求我们不能出现跳跃楼梯的情况,否则会导致我们的索引失效:

按楼梯从低到高,无出现跳跃的情况–此时符合最左前缀原则,索引不会失效

带你把MySQL索引吃透了

出现跳跃的情况直接第一层name都不走,当然都失效

带你把MySQL索引吃透了

走了第一层,但是后续直接第三层,只有出现跳跃情况前的不会失效(此处就只有name成功)

带你把MySQL索引吃透了

同时,这个顺序并不是由我们where中的排列顺序决定,比如: where name=’小米科技’ and status=’1′ and address=’北京市’ where status=’1′ and name=’小米科技’ and address=’北京市’

这两个尽管where中字段的顺序不一样,第二个看起来越级了,但实际上效果是一样的

关于这个查询优化器,后续文章我们也会谈谈MySQL的逻辑架构与存储引擎索引设计原则针对表查询频次高,且数据量多的表针对字段最好从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。其他原则最好用唯一索引,区分度越高,使用索引的效率越高不是越多越好,维护也需要时间和空间代价,建议单张表索引不超过 5 个

比如:

当我们where中根据status和address两个字段来查询时,数据库只会选择最优的一个索引,不会所有单列索引都使用。

最优的索引:具体是指所查询表中,辨识度最高(所占比例最少)的索引列,比如此处address中有一个辨识度很高的 ‘西安市’数据

带你把MySQL索引吃透了

使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。利用最左前缀,比如有N个字段,我们不一定需要创建N个索引,可以用复合索引

创建复合索引: CREATE INDEX idx_name_email_status ON tb_seller(name,email,status);就相当于 对name 创建索引 ; 对name , email 创建了索引 ; 对name , email, status 创建了索引 ;

举个栗子

假设我们有这么一个表,id为主键,没有创建索引:

CREATE TABLE `tuser` ( `id` int(11) NOT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`),) ENGINE=InnoDB

如果要在此处建立复合索引,我们要遵循什么原则呢?

通过调整顺序,可以少维护一个索引比如我们的业务需求里边,有如下两种查询方式: 根据name查询 根据name和age查询

如果我们建立索引(age,name),由于最左前缀原则,我们这个索引能实现的是根据age,根据age和name查询,并不能单纯根据name查询(因为跳跃了),为了实现我们的需求,我们还得再建立一个name索引;

而如果我们通过调整顺序,改成(name,age),就能实现我们的需求了,无需再维护一个name索引,这就是通过调整顺序,可以少维护一个索引。

考虑空间->短索引比如我们的业务需求里边,有以下两种查询方式: 根据name查询 根据age查询 根据name和age查询

我们有两种方案:

建立联合索引(name,age),建立单列索引:age索引。建立联合索引(age,name),建立单列索引:name索引。

这两种方案都能实现我们的需求,这个时候我们就要考虑空间了,name字段是比age字段大的,显然方案1所耗费的空间是更小的,所以我们更倾向于方案1

何时建立索引where中的查询字段查询中与其他表关联的字段,比如外键排序的字段统计或分组的字段何时达咩索引表中数据量很少经常改动的表频繁更新的字段数据重复且分布均匀的表字段(比如包含了很多重复数据,那此时多叉树的二分查找,其实用处不大,可以理解为O(logn)退化了)索引相关语法创建索引

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type]ON tbl_name(index_col_name,...)index_col_name : column_name[(length)][ASC | DESC]

查找索引

select index from tbl_name\G;

删除索引

drop INDEX index_name on tbl_name ;

变更索引

1). alter table tb_name add primary key(column_list); 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL 2). alter table tb_name add unique index_name(column_list); 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次) 3). alter table tb_name add index index_name(column_list); 添加普通索引, 索引值可以出现多次。 4). alter table tb_name add fulltext index_name(column_list); 该语句指定了索引为FULLTEXT, 用于全文索引

查看索引使用情况

show status like 'Handler_read%'; -- 查看当前会话索引使用情况show global status like 'Handler_read%'; -- 查看全局索引使用情况

Handler_read_first:索引中第一条被读的次数。如果较高,表示服务器正执行大量全索引扫描(这个值越低越好)。

Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的性能改善不高,因为索引不经常使用(这个值越高越好)。

Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。

Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY … DESC。

Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应该建立索引来补救。

Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。

总结索引简单来说就是一个排好序的数据结构,可以方便我们检索数据,而不需要盲目的进行全表扫描。索引底层有很多种实现结构,这篇主要只是讲解了BTREE索引,如果对树这一数据结构还不太熟悉的小伙伴,可以关注我后续数据结构专栏,会整理关于普通树,二叉树,二叉排序树的文章。索引分类:主键索引辅助索引索引的相关设计原则,索引虽好,但也不可贪杯,不能为了用索引而建索引。索引的相关语法,很容易上手的。查看索引的使用情况。mysql视频教学


推荐阅读
  • 深入分析十大PHP开发框架
    随着PHP技术的发展,各类开发框架层出不穷,成为了开发者们热议的话题。本文将详细介绍并对比十款主流的PHP开发框架,旨在帮助开发者根据自身需求选择最合适的工具。 ... [详细]
  • MySQL Debug 模式的实现与应用
    本文详细介绍了如何启用和使用 MySQL 的调试模式,包括编译选项、环境变量配置以及调试信息的解析。通过实际案例展示了如何利用调试模式解决客户端无法连接服务器的问题。 ... [详细]
  • PHP 中 preg_match 函数的 isU 修饰符详解
    本文详细解析 PHP 中 preg_match 函数中 isU 修饰符的具体含义及其应用场景,帮助开发者更好地理解和使用正则表达式。 ... [详细]
  • 前端开发中的代码注释实践与规范
    本文探讨了前端开发过程中代码注释的重要性,不仅有助于个人清晰地回顾自己的编程思路,还能促进团队成员之间的有效沟通。文章将详细介绍HTML、CSS及JavaScript中的注释使用方法,并提出一套实用的注释规范。 ... [详细]
  • Spring Cloud因其强大的功能和灵活性,被誉为开发分布式系统的‘一站式’解决方案。它不仅简化了分布式系统中的常见模式实现,还被广泛应用于企业级生产环境中。本书内容详实,覆盖了从微服务基础到Spring Cloud的高级应用,适合各层次的开发者。 ... [详细]
  • 探讨GET与POST请求数据传输的最大容量
    在Web开发领域,GET和POST是最常见的两种数据传输方法。本文将深入探讨这两种请求方式在不同环境下的数据传输能力及其限制。 ... [详细]
  • 如何解决PHP中时间获取不准确的问题
    本文探讨了在PHP开发过程中遇到的时间获取错误问题,并提供了详细的解决方案,包括通过修改配置文件和编程方法来调整时区设置。 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • Java 中重写与重载的区别
    本文详细解析了 Java 编程语言中重写(Override)和重载(Overload)的概念及其主要区别,帮助开发者更好地理解和应用这两种多态性机制。 ... [详细]
  • 本文将介绍如何利用Python爬虫技术抓取国内主流在线学习平台的数据,并以51CTO学院为例,进行详细的技术解析和实践操作。 ... [详细]
  • 智慧城市建设现状及未来趋势
    随着新基建政策的推进及‘十四五’规划的实施,我国正步入以5G、人工智能等先进技术引领的智慧经济新时代。规划强调加速数字化转型,促进数字政府建设,新基建政策亦倡导城市基础设施的全面数字化。本文探讨了智慧城市的发展背景、全球及国内进展、市场规模、架构设计,以及百度、阿里、腾讯、华为等领军企业在该领域的布局策略。 ... [详细]
  • ServletContext接口在Java Web开发中扮演着重要角色,它提供了一种方式来获取关于整个Web应用程序的信息。通过ServletContext,开发者可以访问初始化参数、共享数据以及应用资源。 ... [详细]
  • 本文探讨如何使用 PHP 进行字符串处理,特别是如何检测一个字符串是否存在于另一个字符串中,并确定其具体位置。通过实例代码展示,帮助读者掌握这一常用功能。 ... [详细]
  • PHP中静态类与静态变量的应用差异探讨
    本文深入探讨了PHP编程语言中静态类与静态变量的具体应用及其差异性,旨在帮助开发者更好地理解和运用这些概念,以提升代码质量和效率。 ... [详细]
  • 本文探讨了如何使用已有的PHP网站来管理和控制Python编写的网络爬虫,包括启动、停止以及动态更改爬虫的目标网址。 ... [详细]
author-avatar
mobiledu2502899835
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有