iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >Mysql索引结合explain分析示例
  • 936
分享到

Mysql索引结合explain分析示例

2024-04-02 19:04:59 936人浏览 独家记忆
摘要

目录简介1.索引分类聚簇索引为什么选择B+树explain简介 Mysql 在我们项目中使用是非常广的,当我们数据量大的时候,就需要考虑建立索引了,我感觉这也是一种以空间换时间的方式

简介

Mysql 在我们项目中使用是非常广的,当我们数据量大的时候,就需要考虑建立索引了,我感觉这也是一种以空间换时间的方式;在我们查询的时候,通过使用索引来提高速度;那么,我们在使用的过程中,怎么判定有没有走索引呢?有一个explain语句来进行分析,根据阿里的Java编程规范,至少类型要提升到range;我那时候就在想为什么要提升到range呢?后来结合mysql的索引终于知道explain和Mysql底层B+树的对应关系;注:以下内容都是基于InnoDB引擎;

1.索引分类

索引分为聚簇索引非聚簇索引;那么,我们先来探讨一下聚簇索引;

聚簇索引

那么在InnoDB中,如果没有定义主键,那么会怎么办?

首先,他会看你有没有定义唯一键;如果有唯一键,那么就会把这个唯一键当作主键来建立索引;如果连唯一键也没有的话,就会默认创建一个隐藏列 row_id 通过这个row_id来建立索引;所以,由于有这个机制(这个机制是为了配合普通索引的),使用Innodb的话,还是,需要有一个主键 最好是递增主键;不用白不用;(还有,就是主键尽量小一点,如果像UUID一样,问题很多 第一:主键被其他普通索引叶子使用,占用空间 第二:插入的时候,需要随机访问I/O,并且,容易导致页分裂)

聚簇索引的结构 假设,我们主键递增,它的结构示意图如下:

这是一个简单示意图:一页数据能存16k 所以,第一层节点数据肯定比这多多了; 但是,我们可以得到一个结论: 对于非叶子节点存的是主键 + 指针 对于叶子节点存的是 主键 + 真实的数据;

普通索引的结构 假设以 create index idx_t1_bcd on t1(b, c, d)来建立索引; 其示意图如下:

对于普通的索引来说,采用的也是B+树结构,但是: 对于 非叶子节点来说存的是 创建索引的字段(b,c,d) + 指向数据指针 对于叶子节点来说 存的是 创建索引的字段(b,c,d) + 主键的指针;

这里由于存的是主键的指针出现会导致回表:普通索引为什么需要这么设计(为什么不存数据)? 个人理解原因如下:

  • 如果,普通索引也要存下数据的话,那么需要内存空间太大了;
  • 如果,普通索引也存数据的话,当发生修改的话,就需要修改全部的数据;

所以,很明显这个普通索引是比聚簇索引占用空间小很多的,这个特性在count(*) 的时候会用到;

那么,为了解决回表问题,覆盖索引来进行解决

为什么选择B+树

刚刚已经介绍了Mysql 聚簇索引和普通索引的特征;那么,现在问题来了?为什么要选择B+树呢?

原因:和Mysql的特性所致:针对磁盘来说 io是它的一大瓶颈,索引的出现是为了快速找到对应的数据,所以说:IO越少效率越好,(就是磁盘页加载到内存次数越少越好) 那么,为什么使用B+树就会加载的少呢?

举例说明: 我们假设待存储数据一行大小是1k; 所以,我们一页可以存16行数据;假设我们的主键id为bigint类型,长度为8字节(如果是int 4字节),而指针大小为6字节;一页 为 16k 16 * 1024 /14 = 1170,所以,我们非节点页,可以存放1170个主键 + 指针;综上:如果是2层节点的B+树;可以存的数据是 1170 * 16 = 18720行数据;

那么,如果是三层的B+树呢?这时候第一页非叶子节点,可以存1170个主键+ 指针(指向的是非叶子节点) 第二页非叶子节点,也可以存1170个主键 + 指针(指向叶子节点);第三层 每一页 可以存16行数据;所以,总共可以存 1170 * 1170 * 16行数据;(这已经是千万条数据了)而且,第一层或者第二层非叶子节点一般是是缓存在内存中的,其实千万条数据找一或两次就可以了;其他的以此类推; 如果,采用B树,因为它的非叶子节点中也是存数据的层级会高过B+树;

原因2:使用B+树结构时,因为数据是存在叶子节点中,所以,对于访问查询找到第一个值,就可以通过叶子节点的双向链表进行遍历查询;而如果B树,就需要采用中序遍历;

综上: 1.B+树层级会比较低 2.对范围查询效率比较高;

explain

介绍完Mysql索引结构,我们可以来讲解explain了;

这是explain的字段,我记得我刚刚开始的时候是怎么都记不住;后来和索引建立联系以后就记住了;
id :表示表的加载顺序,id 越大越先查询 用于大表驱动小表;如果相关,就从上到下执行;
type: 查询使用了那种类型 从最好到最差 system > const > eq_ref > ref > range > index > ALL;
const:只匹配一次 出行在主键索引或者唯一索引
ref : 非唯一性索引扫描,返回匹配某个单个值的所在行; 就是通过一个where 条件找到一条或多条数据;
range: 范围查询时使用到;最低标准了;
index: 只遍历索引树 比全表扫描好一点点 因为通常来说索引文件比数据文件小;
all : 全表扫描

row :通过采用函数推算出来的要读的条数,涉及索引的选择,正常情况下误差不会很大; extra: Using filesort 文件排序 需要对找出来的数据进行外部排序,不能使用表内索引完成排序; 慢 需要优化
Using temporary : 使用了临时表来保存中间结果 更慢 需要优化
Using index : 使用了覆盖索引 Using where 使用了Where 这两个不用优化
如果,对Using filesort Using temporary为什么慢感兴趣的同学,可以查看我的另一篇文章 Using filesort Using temporary为什么这么慢

从索引树的角度分析为什么ref>range>index

比如说:where key = 4 这个时候,它首先在第一页进行查找(这里它对链表处理过,引入了数组,为了查找快速,使用的是二分查找) 然后,找到数据指针是0005,所以就去0005数据页中,进行查找,(在页中查找也是使用二分查找)找到了第一条数据key = 4,然后,只要找下一条,看看是不是key != 4 如果,不等于4,那么,就找完了;这是ref级别的过程;
然后,where key >= 4;同理,先找到key = 4,然后,因为大于4,所以,就按照叶子节点中的指针向后找,找到底,这个是type = range 的情况;
至于 type = index 其实就是对整个索引树进行遍历 ,比如说:我创建了普通索引 user(姓名,身份证号) 我想把所有的身份证号找出来,这个时候,就可能使用基于索引树的全表扫描了,因为,索引树相对来说内容小一点,如果,全部扫描的话,内存中没有对应数据页还得都去找出来; 通过,这样推理,可以感受到 ref > range > index;

最左前缀原则理解 我们都知道有最左前缀原则,那么,为什么会有这个原则呢?

还是以他为例:因为B+树先是按照b列的值排序的,在b列的值相同的情况下才使用c列进行排序;也就是说b列的值不同的记录中c的值可能是无序的。而现在你跳过b列直接根据c的值去查找,这是做不到的。 所以说:下面sql语句是没有用的;

select * from t1 where c = 1;

但是,针对下面这条语句:从索引层面这个C是用不上的,从系统性能角度,C又是用的上的,它这叫做索引下推,因为它可以根据b = 1的双向链表相后推的时候,直接把不符合条件的C排除掉了;不用先回表查出数据,在进行排除;

select * from t1 where b > 1 and c > 1;

到此这篇关于Mysql索引结合explain分析示例的文章就介绍到这了,更多相关Mysql explain 索引内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Mysql索引结合explain分析示例

本文链接: https://www.lsjlt.com/news/139623.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • sql怎么查看表的索引
    通过查询系统表,可以获取表的索引信息,包括索引名称、是否唯一、索引类型、索引列和行数。常用系统表有:mysql 的 information_schema.statistics、postg...
    99+
    2024-05-14
    mysql oracle
  • sql怎么查看索引
    您可以使用 sql 通过以下方法查看索引:show indexes 语句:显示表中定义的索引列表及其信息。explain 语句:显示查询计划,其中包含用于执行查询的索引。informat...
    99+
    2024-05-14
  • sql怎么查看存储过程
    如何查看 sql 存储过程的源代码:使用 show create procedure 语句直接获取创建脚本。查询 information_schema.routines 表的 routi...
    99+
    2024-05-14
  • sql怎么查看视图表
    要查看视图表,可以使用以下步骤:使用 select 语句获取视图中的数据。使用 desc 语句查看视图的架构。使用 explain 语句分析视图的执行计划。使用 dbms 提供...
    99+
    2024-05-14
    oracle python
  • sql怎么查看创建的视图
    可以通过sql查询查看已创建的视图,具体步骤包括:连接到数据库并执行查询select * from information_schema.views;查询结果将显示视图的名称、...
    99+
    2024-05-14
    mysql
  • sql怎么用循环语句实现查询
    可以通过 do 和 while 语句创建循环,并在循环内执行查询,详细步骤包括:定义循环变量设置循环初始值循环执行查询更新循环变量执行查询循环退出条件 SQL 中使用循环语句实现查询 ...
    99+
    2024-05-14
  • sql怎么用代码修改表中数据
    通过 sql 代码修改表中数据的方法包括:修改单个记录:使用 update 语句设置列值并指定条件。修改多条记录:在 update 语句中指定多个条件来修改满足条件的所有记录。增加新列:...
    99+
    2024-05-14
  • sql怎么用命令创建数据库
    在 sql 中使用 create database 命令创建新数据库,其语法包含以下步骤:指定数据库名称。指定数据库文件和日志文件的位置(可选)。指定数据库大小、最大大小和文件增长(可选...
    99+
    2024-05-14
  • sql怎么用身份证提取年龄
    sql 中提取身份证号码中的年龄的方法:提取出生日期部分(身份证号码中第 7-14 位);使用 to_date 函数转换为日期格式;使用 extract 函数计算与当前日期之间的年差。 ...
    99+
    2024-05-14
  • sql怎么看字段长度
    有两种方法可查看 sql 中的字段长度:使用 information_schema 架构,其中包含元数据信息,可用于查询字段长度。使用内建函数,如 length(),其适用于字符串数据类...
    99+
    2024-05-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作