Mysql从入门到入神之(四)B+树索引

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

絮叨


我们继续来探索mysql。前面我们了解了mysql的索引的一些基础知识,今天我们来康康B+树索引

来复习一下一下昨天的 首先是InnoDB的页存储结构,我们知道 多个不同的页组成的是一个双向链表,而每个页里面的数据行会按主键的大小组成一个单向链表,并且每4到8个数据组成一个槽,每个槽存储在pageDirectoy里面 ,当我们要查询页的行数据的时候,可以先定位到页,然后用2分法定位到槽,然后遍历槽,来定位到当前行的数据。(大佬画的图,大家可以好好理解一下)

其中页a、页b、页c ... 页n 这些页可以不在物理结构上相连,只要通过双向链表相关联即可。


没有索引下的查找数据的方式


  • 第一种,查询的是id主键的一个确定值,这个好像还不是那么难,首先遍历所有的页,定位到页,从页里面找到槽,从槽里面找到当前行,所以这样说的话,这种如果页数比较多的话,查询也会很慢
  • 第二种,也就是我们说的全表扫描,一个个去遍历,最后来找到这一行数据,因为这种查询的会非常的慢,所以呢我们的索引就派上用场了


InnoDB中的索引方案

  • InnoDB是使用页来作为管理存储空间的基本单位,也就是最多能保证16KB的连续存储空间,而随着表中记录数量的增多,需要非常大的连续的存储空间才能把所有的目录项都放下,这对记录数量非常多的表是不现实的。
  • 我们时常会对记录进行增删,假设我们把页中的记录都删除了,页也就没有存在的必要了,那意味着目录项也就没有存在的必要了,这就需要把目录项后的目录项都向前移动一下,这种牵一发而动全身的设计不是什么好主意~


它是怎么来实现 ,页记录 和用户用户记录 ,它每个行数据中又一个record_type 这个既可以表示,页记录 和用户用户记。它有以下的4种取值方式

  • 0:普通的用户记录
  • 1:目录项记录
  • 2:最小记录
  • 3:最大记录


不论是存放用户记录的数据页,还是存放目录项记录的数据页,我们都把它们存放到B+树这个数据结构中了,所以我们也称这些数据页为节点。从图中可以看出来,我们的实际用户记录其实都存放在B+树的最底层的节点上,这些节点也被称为叶子节点或叶节点,其余用来存放目录项的节点称为非叶子节点或者内节点,其中B+树最上边的那个节点也称为根节点。


聚簇索引


上面的B+数 本身就是一个主键索引 我们也叫聚簇索引,它有两个特点

  • 使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:
  • 存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表。 (树的每一层都是一个双向链表)
  • 各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表。(最后一层的用户数据层也是一个双向链表)
  • 页内的记录是按照主键的大小顺序排成一个单向链表。(页内是一个单休链表,和一个有着顺序的槽目录)
  • B+树的叶子节点存储的是完整的用户记录。所谓完整的用户记录,就是指这个记录中存储了所有列的值(包括隐藏列)。

我们把具有这两种特性的B+树称为聚簇索引,所有完整的用户记录都存放在这个聚簇索引的叶子节点处。这种聚簇索引并不需要我们在MySQL语句中显式的使用INDEX语句去创建(后边会介绍索引相关的语句),InnoDB存储引擎会自动的为我们创建聚簇索引。另外有趣的一点是,在InnoDB存储引擎中,聚簇索引就是数据的存储方式(所有的用户记录都存储在了叶子节点),也就是所谓的索引即数据,数据即索引。


二级索引


大家有木有发现,上边介绍的聚簇索引只能在搜索条件是主键值时才能发挥作用,因为B+树中的数据都是按照主键进行排序的。那如果我们想以别的列作为搜索条件该咋办呢?难道只能从头到尾沿着链表依次遍历记录么?

不,我们可以多建几棵B+树,不同的B+树中的数据采用不同的排序规则。比方说我们用c2列的大小作为数据页、页中记录的排序规则,再建一棵B+树,效果如下图所示:

其实这个呢,和上面的也差不都就是说这个说子节点存放的是我们的索引列+我们的主键的数据。如果我们想要当前那一行的所有数据的话,我们是需要做一次回表操作的。


联合索引



我们也可以同时以多个列的大小作为排序规则,也就是同时为多个列建立索引,比方说我们想让B+树按照c2和c3列的大小进行排序,这个包含两层含义:

  • 先把各个记录和页按照c2列进行排序。
  • 在记录的c2列相同的情况下,采用c3列进行排序

类似于这种,就是先把第一个列做好索引,然后再排第二个列,必须按先后顺序来,所以我们所说的前缀索引就是这样来的。


索引的代价


在熟悉了B+树索引原理之后,本篇文章的主题是唠叨如何更好的使用索引,虽然索引是个好东西,可不能乱建,在介绍如何更好的使用索引之前先要了解一下使用这玩意儿的代价,它在空间和时间上都会拖后腿:

  • 空间上的代价
  • 这个是显而易见的,每建立一个索引都要为它建立一棵B+树,每一棵B+树的每一个节点都是一个数据页,一个页默认会占用16KB的存储空间,一棵很大的B+树由许多数据页组成,那可是很大的一片存储空间呢。
  • 时间上的代价
  • 每次对表中的数据进行增、删、改操作时,都需要去修改各个B+树索引。而且我们讲过,B+树每层节点都是按照索引列的值从小到大的顺序排序而组成了双向链表。不论是叶子节点中的记录,还是内节点中的记录(也就是不论是用户记录还是目录项记录)都是按照索引列的值从小到大的顺序而形成了一个单向链表。而增、删、改操作可能会对节点和记录的排序造成破坏,所以存储引擎需要额外的时间进行一些记录移位,页面分裂、页面回收啥的操作来维护好节点和记录的排序。如果我们建了许多索引,每个索引对应的B+树都要进行相关的维护操作,这还能不给性能拖后腿么?


创建高性能索引原则


独立的列

什么意思呢?就是我们where = 后面的条件,必须是独立的一个列,不能是id+1,这种计算,所以有一个原则就是始终将索引列单独放在比较符合的一侧。


前缀索引

比如一个字符串很长,然后你要给这个字段建立索引,如果说他们前几个字段的识别度很高了话,就建议建立一个前缀索引。这样就可以大大的节省索引空间


多列索引

一个常见的错误就是,给每个列都建立一个索引,这样是错误的,还有就是建立联合索引的时候的顺序是随便填的,这种方式也是错误的。如果你用explain 关键字看到了 索引合并的信息,就说明你这个索引看是否能否优化。


选择合适的索引顺序

假设你有2个列要建立组合索引,那么这个组合索引的列的字段到底是哪个先 哪个后呢?这个是没有一定的标准的,但是默认的条件是如果你有数量少的字段尽量是放到前面,在不考虑,分组的条件下,这种情况确实是比较快的。


覆盖索引

覆盖索引的意思就是我们建立索引的时候,我把需要查询的条件一起建立一个联合索引,那么查询这些数据的时候,我们就不需要回表操作了。


尽量用索引扫描来排序

如果explain中type的结果是index,就说明mysql使用了索引扫描来做排序,


未使用的索引

如果发现有些索引是一直不会使用的索引,建议删除它。


不可以使用索引进行排序的几种情况

  • ASC、DESC混用 对于使用联合索引进行排序的场景,我们要求各个排序列的排序顺序是一致的,也就是要么各个列都是ASC规则排序,要么都是DESC规则排序。
  • WHERE子句中出现非排序使用到的索引列


总结


  • 索引并不是想建就建,凡事都是有代价的吗,我们只能说权衡利弊
  • 索引通用的一些场景
  • 等值查询
  • 匹配组合索引左边的索引
  • 匹配组合索引的左边的索引的范围查询
  • 匹配等值查询和范围查询
  • 分组查询
  • 排序
  • 索引的一些注意事项
  • 只为搜索,分组,排序的列建立索引
  • 只为数据的识别度高的列建立索引(例如性别就不建议建立索引)
  • 对于字符串的列,如果它的能建立前缀索引,最好就建立前缀索引
  • 为了让页尽量减少页分裂的情况,最好给主键建立自增
  • 删除不必要的索引
  • 如果能用覆盖索引的尽量用覆盖索引,减少回表的次数。


结尾


我们下章继续再战。 文章部分内容出自 MySQL 是怎样运行的:从根儿上理解 MySQL,

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
13天前
|
SQL 关系型数据库 MySQL
网安入门之MySQL后端基础
《网安入门之MySQL后端基础》简介: 本文介绍了数据库及MySQL的基础知识,涵盖数据库的概念、结构与操作。数据库是组织化存储数据的集合,通过表、列、行等结构实现高效管理。MySQL作为开源的关系型数据库管理系统,广泛应用于Web开发。文中详细讲解了MySQL的基本操作,如增(INSERT)、删(DELETE)、改(UPDATE)、查(SELECT)等语句的使用方法,并介绍了数据库事务的ACID特性。此外,还探讨了SQL注入攻击的风险及防范措施,强调了预处理语句的重要性。最后,简述了PHP中mysqli扩展的使用方法,包括连接数据库、执行查询和关闭连接等步骤。
|
1月前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
177 9
|
17天前
|
SQL 存储 关系型数据库
MySQL秘籍之索引与查询优化实战指南
最左前缀原则。不冗余原则。最大选择性原则。所谓前缀索引,说白了就是对文本的前几个字符建立索引(具体是几个字符在建立索引时去指定),比如以产品名称的前 10 位来建索引,这样建立起来的索引更小,查询效率更快!
79 22
 MySQL秘籍之索引与查询优化实战指南
|
18天前
|
存储 关系型数据库 MySQL
MySQL中为什么要使用索引合并(Index Merge)?
通过这些内容的详细介绍和实际案例分析,希望能帮助您深入理解索引合并及其在MySQL中的
68 10
|
1月前
|
存储 Oracle 关系型数据库
索引在手,查询无忧:MySQL索引简介
MySQL 是一款广泛使用的关系型数据库管理系统,在2024年5月的DB-Engines排名中得分1084,仅次于Oracle。本文介绍MySQL索引的工作原理和类型,包括B+Tree、Hash、Full-text索引,以及主键、唯一、普通索引等,帮助开发者优化查询性能。索引类似于图书馆的分类系统,能快速定位数据行,极大提高检索效率。
59 8
|
25天前
|
存储 关系型数据库 MySQL
【MYSQL】 ——索引(B树B+树)、设计栈
索引的特点,使用场景,操作,底层结构,B树B+树,MYSQL设计栈
|
1天前
|
缓存 关系型数据库 MySQL
【深入了解MySQL】优化查询性能与数据库设计的深度总结
本文详细介绍了MySQL查询优化和数据库设计技巧,涵盖基础优化、高级技巧及性能监控。
10 0
|
28天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
56 3
|
28天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
66 3
|
28天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE 'log_%';`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
86 2