【mysql】优化系列文章之一-索引

news2025/1/17 22:56:24

mysql优化系列

不是教程,不是官方文档,而是自己实战的点滴记录,不一定适合新手和系统学习者
第一章 mysql索引


文章目录

  • mysql优化系列
  • 前言
  • 1、Mysql索引
  • 2、B+ Tree
    • 2.1.特点
    • 2.2. 结构分解
    • 2.3. 例题分析
    • 2.4. 验证索引
    • 2.5.索引插入耗时
  • 3. MySQL 中 B+ 树索引的设计与管理
  • 总结


前言

不是教程,不是官方文档,而是自己实战的点滴记录,不一定适合新手和系统学习者。本篇文章尝试回答以下几个问题:

  1. B+ tree 为什么快?
  2. B+ tree 在存储多少层后(表的数据有多大后)性能开始显著下降?
  3. 建了几个索引,是否已经用到了,如何确认是否已经用到了?效果如何?

1、Mysql索引

什么是索引?
索引是提升查询速度的一种数据结构。
使用它有什么优缺点?
索引能提升查询速度,它在插入时对数据进行了排序(显而易见,它的缺点是影响插入或者更新的性能)。
索引都有哪些?
索引是一门排序的艺术,有效地设计并创建索引,会提升数据库系统的整体性能。在MySQL 8.0 版本中,InnoDB 存储引擎支持的索引有 B+ 树索引、全文索引、R 树索引。
本文章主要关注哪个索引,为什么?
B+ 树索引是数据库系统中最为常见的一种索引数据结构,是目前为止排序最有效率的数据结构。像二叉树,哈希索引、红黑树、SkipList,在海量数据基于磁盘存储效率方面远不如 B+ 树索引高效。数据结构一般仅用于内存对象,基于磁盘的数据排序与存储,最有效的依然是 B+ 树索引。

2、B+ Tree

2.1.特点

B+树索引的特点: 基于磁盘的平衡树,但树非常矮,通常为 3~4 层,能存放千万到上亿的排序数据。树矮访问效率高,从千万或上亿数据里查询一条数据,只用 3、4 次 I/O。

又因为固态硬盘每秒能执行至少 10000 次 I/O ,所以查询一条数据,哪怕全部在磁盘上,也只需要 0.003 ~ 0.004 秒。另外, B+ 树矮,在做排序时,只需要比较 3~4 次就能定位数据需要插入的位置,排序效率好。

2.2. 结构分解

B+ 树索引由根节点(root node)、中间节点(non leaf node)、叶子节点(leaf node)组成,其中叶子节点存放所有排序后的数据。当然也有特殊情况,比如高度为 1 的B+ 树索引:
在这里插入图片描述
上图中,第一个列就是 B+ 树索引排序的列.它是表 User 中的列 id,类型为 8 字节的 BIGINT,所以列 userId 就是索引键(key),类似下表:

CREATE TABLE User (

  id BIGINT AUTO_INCREMENT PRIMARY KEY,

  name VARCHAR(128) NOT NULL,

  sex CHAR(6) NOT NULL,

  registerDate DATETIME NOT NULL,
  ...
)

B+ 树都是从高度为 1 的树开始,然后根据数据的插入,增加树的高度。需要强调的是:索引是对记录进行排序, 高度为 1 的 B+ 树索引中,存放的记录都已经排序好了,若要在一个叶子节点内再进行查询,只进行二叉查找,就能快速定位数据。

可随着插入 B+ 树索引的记录变多,1个页(16K)无法存放这么多数据,所以会发生 B+ 树的分裂,B+ 树的高度变为 2,当 B+ 树的高度大于等于 2 时,根节点和中间节点存放的是索引键对,由(索引键、指针)组成。

索引键就是排序的列,而指针是指向下一层的地址,在 MySQL 的 InnoDB 存储引擎中占用 6 个字节。下图显示了 B+ 树高度为 2 时,B+ 树索引的样子:
在这里插入图片描述
可以看到,在上面的B+树索引中,若要查询索引键值为 5 的记录,则首先查找根节点,查到键值对(20,地址),这表示小于 20 的记录在地址指向的下一层叶子节点中。接着根据下一层地址就可以找到最左边的叶子节点,在叶子节点中根据二叉查找就能找到索引键值为 5 的记录。

2.3. 例题分析

那一个高度为 2 的 B+ 树索引,理论上最多能存放多少行记录呢?-----不提数据,只是泛泛的说的教程,都是在耍流氓!!!!
在 MySQL InnoDB 存储引擎中,一个页的大小为 16K,在上面的表 User 中,键值 userId 是BIGINT 类型,则:
根节点能最多存放以下多个键值对 = 16K / 键值对大小(8+6) ≈ 1100
再假设表 User 中,每条记录的大小为 500 字节,(id BIGINT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(128) sex CHAR(6) registerDate DATETIME,… 这些字段所占用的空间加起来是500字节 )则:

叶子节点能存放的最多记录为 = 16K / 每条记录大小 ≈ 32

综上,树高度为 2 的 B+ 树索引,最多能存放的记录数为:

总记录数 = 1100 * 32 =  35,200

也就是说,35200 条记录排序后,生成的 B+ 树索引高度为 2。在 35200 条记录中根据索引键查询一条记录只需要查询 2 个页,一个根叶,一个叶子节点,就能定位到记录所在的页。

所以再看一个高度为3的B+ tree:
高度为 3 的 B+ 树索引本质上与高度 2 的索引一致,如下图所示,
在这里插入图片描述
同理,树高度为 3 的 B+ 树索引,最多能存放的记录数为:

总记录数 = 1100(根节点) * 1100(中间节点) * 32 =  38,720,000

数据来了:高度为 3 的 B+ 树索引竟然能存放 3800W 条记录。在 3800W 条记录中定位一条记录,只需要查询 3 个页。

现实骨感:不过,在真实环境中,每个页其实利用率并没有这么高,还会存在一些碎片的情况,我们假设每个页的使用率为60%,则:
在这里插入图片描述
表格显示了 B+ 树的威力,即在 50 多亿的数据中,根据索引键值查询记录,只需要 4 次 I/O,大概仅需 0.004 秒。如果这些查询的页已经被缓存在内存缓冲池中,查询性能会更快。

如何整理碎片是另外的话题,此文章不做探究。

2.4. 验证索引

在数据库中,上述的索引查询请求对应的 SQL 语句为:

SELECT * FROM User WHERE id = ?

用户可以通过命令 EXPLAIN 查看是否使用索引:

mysql> EXPLAIN SELECT * FROM  User WHERE id = 1\G

********************** 1. row **********************

           id: 1

  select_type: SIMPLE

        table: User

   partitions: NULL

         type: const

possible_keys: PRIMARY

          key: PRIMARY

      key_len: 8

          ref: const

         rows: 1

     filtered: 100.00

        Extra: NULL

具体explain的各个项目代表什么,自行百度。这里只说关键点。
在输出的 EXPLIAN 结果中,可以看到列 key 显示 PRIMARY,这表示根据主键索引进行查询。若没有根据索引进行查询,如根据性别进行查询,则会显示类似如下内容:

mysql> EXPLAIN SELECT * FROM User WHERE sex = 'male'\G

********************** 1. row **********************

           id: 1

  select_type: SIMPLE

        table: User

   partitions: NULL

         type: ALL

possible_keys: NULL

          key: NULL

      key_len: NULL

          ref: NULL

         rows: 986400

     filtered: 50.00

        Extra: Using where

注意rows,type,possible_keys

2.5.索引插入耗时

B+ 树的查询高效是要付出代价的,就是我们前面说的插入性能问题
B+ 树在插入时就对要对数据进行排序,但排序的开销其实并没有你想象得那么大,因为排序是 CPU 操作(当前一个时钟周期 CPU 能处理上亿指令)
真正的开销在于 B+ 树索引的维护,保证数据排序,这里存在两种不同数据类型的插入情况。

  1. 数据顺序(或逆序)插入: B+ 树索引的维护代价非常小,叶子节点都是从左往右进行插入,比较典型的是自增 ID 的插入、时间的插入(若在自增 ID 上创建索引,时间列上创建索引,则 B+ 树插入通常是比较快的)。
  2. 数据无序插入: B+ 树为了维护排序,需要对页进行分裂、旋转等开销较大的操作,另外,即便对于固态硬盘,随机写的性能也不如顺序写,所以磁盘性能也会收到较大影响。比较典型的是用户昵称,每个用户注册时,昵称是随意取的,若在昵称上创建索引,插入是无序的,索引维护需要的开销会比较大。

所以对于 B+ 树索引,在 MySQL 数据库设计中,仅要求主键的索引设计为顺序,比如使用自增,或使用函数 UUID_TO_BIN 排序的 UUID,而不用无序值做主键。

3. MySQL 中 B+ 树索引的设计与管理

干货来了!!!泛泛的教程不会讲这些,是他不想讲么,显示不是—他也不会。
查询表 mysql.innodb_index_stats 查看每个索引的大致情况:

SELECT 

table_name,index_name,stat_name,

stat_value,stat_description 

FROM innodb_index_stats 

WHERE table_name = 'orders' and index_name = 'PRIMARY';

+----------+------------+-----------+------------+------------------+

|table_name| index_name | stat_name | stat_value |stat_description  |

+----------+-------------------+------------+------------+----------+

| orders | PRIMARY|n_diff_pfx01|5778522     | O_ORDERKEY            |

| orders | PRIMARY|n_leaf_pages|48867 | Number of leaf pages        |

| orders | PRIMARY|size        |49024 | Number of pages in the index|

+--------+--------+------------+------+-----------------------------+

3 rows in set (0.00 sec)

从上面的结果中可以看到,表 orders 中的主键索引,大约有 5778522 条记录,其中叶子节点一共有 48867 个页,索引所有页的数量为 49024。根据上面的介绍,你可以推理出非叶节点的数量为 49024 ~ 48867,等于 157 个页。

MySQL规范或者面试宝典中写道一张表的索引不能超过 5 个。我之前也背后这些(少不更事啊),2年前我所在的公司,还把这条写入了开发规范**。-----NoneSense 胡说八道,业务的确需要很多不同维度进行查询,就该创建对应多索引。**
真正的问题: xjb建了若干索引,实际用不到。因为查询优化器根本不会选择低效索引(possible_key 不一定会使用,进而仍然走全表扫描type:all),创建和维护索引又占用了空间,影响插入性能。

那么问题来了,如何知 道B+树索引未被使用过呢?
查询表sys.schema_unused_indexes,查看有哪些索引一直未被使用过,可以被废弃

SELECT * FROM schema_unused_indexes

WHERE object_schema != 'performance_schema';

+---------------+-------------+--------------+

| object_schema | object_name | index_name   |

+---------------+-------------+--------------+

| sbtest        | sbtest1     | k_1          |

| sbtest        | sbtest2     | k_2          |

| sbtest        | sbtest3     | k_3          |

| sbtest        | sbtest4     | k_4          |

| tpch          | customer    | CUSTOMER_FK1 |

| tpch          | lineitem    | LINEITEM_FK2 |

| tpch          | nation      | NATION_FK1   |

| tpch          | orders      | ORDERS_FK1   |

| tpch          | partsupp    | PARTSUPP_FK1 |

| tpch          | supplier    | SUPPLIER_FK1 |

+---------------+-------------+--------------+

如果数据库运行时间比较长,而且索引的创建时间也比较久,索引还出现在上述结果中,就要删除这些没有用的索引。
小心驶得万年船—
MySQL 8.0 版本推出了索引不可见(Invisible)功能。在删除废弃索引前,将索引设置为对优化器不可见,然后观察业务是否有影响。

ALTER TABLE t1 

ALTER INDEX idx_name INVISIBLE/VISIBLE;

总结

以上就是今天要讲的内容。也是我抄的,但是感觉这个有道理,比其它的教程强很多。欢迎交流、拍砖。

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

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

相关文章

Oracle数据库同步复制工具Beedup产品功能(一)

1、全量复制 Beedup全量复制功能通过遍历比对主从库用户模式及其下包含的各类对象来保证主从库的相关对象一致性。 支持角色、用户、架构、登录用户、表 (列定义 主外键 索引)、视图存储过程、函数、触发器、类型、类型体、包、包体、序列、同义词、数据库链接等对象复制全量…

技术干货 | 人大金仓KFS基于分区索引的分片入库技术解析

在之前的文章《技术干货:人大金仓KFS精准过滤和分片并行入库技术解析》中,KFS利用分片并行入库技术,解决了某金融POC数据同步项目中数据入库持续积压问题。经过优化后,在200并发的压测场景中,整体同步性能指标从压测30…

基于BP神经网络、RBF神经网络以及PSO优化的RBF神经网络进行数据的预测(Matlab代码实现)

💥💥💥💞💞💞欢迎来到本博客❤️❤️❤️💥💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑…

IT30--IT之职能部门(3年之约已满)

IT作为一个职能部门,肯定跟业务不同,具体有哪些事情要做,我们一一道来。 年终规划的二三事 组织体系规划及梳理 预算编制 今天我们先来说说组织体系规划。 1 从愿景使命价值观到行动及思考方法 无论是企业还是部门,软文件建设肯…

【信息检索与数据挖掘期末笔记】(六)Link Analysis

Web图 将Web当做有向图 节点:网页 边:超链接 PageRank 不同网页的重要性是不同的,在web-graph中,节点之间的连接性有巨大的差异。我们根据链接结果来对网页进行排序 想法:用链接来投票 如果有更多的链接指向一个网…

Linux Shell 编程,Shell 变量详解

Linux Shell 编程,Shell 变量详解1.第一个shell脚本2.Shell 变量初探3.位置参数变量4.预定义变量1.第一个shell脚本 打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 hello.sh,扩展名为 sh(sh代表shell&#xff09…

【算法】面试题 - 链表(附讲解视频)

链表相关面试题876. 链表的中间结点206. 反转链表86. 分隔链表160. 相交链表141. 环形链表问题:快慢指针为什么一定会相遇142. 环形链表 II问题:如何确认入口237. 删除链表中的节点19. 删除链表的倒数第 N 个结点21. 合并两个有序链表23. 合并K个升序链表…

【记忆增强深度条件展开网络】

Memory-augmented Deep Conditional Unfolding Network for Pan-sharpening (面向全色锐化的记忆增强深度条件展开网络) 全色锐化旨在为遥感系统获取高分辨率的多光谱图像,基于深度学习的方法已经取得了显著的成功。然而,大多数…

使用iServer rest api如何实现构建巷道效果

作者:刘大 背景 在实际生产环境中,特别是在采矿,公路建设项目上,我们往往会接触下图所示的巷道,那么在Web端如何快速通过线数据构建巷道模型呢?下面我们来详细说下 使用方式 第一步: 在iServe…

反垃圾邮件系统|基于Springboot+vue 实现反垃圾邮件系统

作者主页:编程指南针 作者简介:Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容:Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

servlet(二)文件的上传

servlet实现文件的上传 文件上传是一个web应用常见的功能 比如:QQ头像,就使用了上传。 邮箱中也有附件的上传和下载功能。 OA系统中审批有附件材料的上传。 1.1前端需要有个form表单标签 methodpost请求 (因为post请求是没有长度限制,get…

Computer Graphics From Scratch - Chapter 7

系列文章目录 简介:Computer Graphics From Scratch-《从零开始的计算机图形学》简介 第一章: Computer Graphics From Scratch - Chapter 1 介绍性概念 第二章:Computer Graphics From Scratch - Chapter 2 基本光线追踪 第三章:Computer Gr…

新生儿喝奶后不要马上放回床上睡觉,为宝宝健康着想,先做1件事

看到一个问题,题主问,新生儿喝完奶能马上放回床上睡觉吗?可以吗?也许每个人都认为照顾新生儿是一件非常简单的事情,因为新生儿几乎整天都在睡觉。当他们饿的时候,他们会让他们的宝宝吃牛奶。他们吃饱了就要…

博客搭建教程(一):静态博客 GitHub + Gridea

同步blog文章 注册一个 Github 账号并创建仓库 注册Github账号 如果你没有 Github 的账号,那么可以进入 官网 开始注册(注意一下用户名的填写,如果不使用自定义域名,用户名将会是你的 Github 分配给你的域名,例如你的…

D. George and Interesting Graph(最大匹配)

Problem - 387D - Codeforces 乔治喜欢图表。最重要的是,他喜欢有趣的图。我们将假设一个有向图是有趣的,如果它符合以下标准。 该图不包含任何多弧。 有一个顶点v(我们称她为中心),这样对于图形u的任何顶点&#xff…

信息网络传播视听节目服务单位的设立与经营

一、行业准入 (一)网络视听业务准入范围 利用公共互联网(含移动互联网)向计算机、手机用户提供视听节目服务(不含交互式网络电视(IPTV)、互联网电视、专网手机电视业务)业务的&…

几个小设置让 mac 更好用

今天在 youtube 上看到一个视频[1],讲新 mac 到手后一定要做的几个设置,有几个之前我不知道的小设置,非常好用,看完马上就用上了。一些常用的就不列了,比如说设置点按、三指拖拽,不知道的可以去搜索了解&am…

【Python数据可视化】使用geoplotlib绘制地理空间数据

geoplotlib前言一、安装geoplotlib包二、读取csv数据使用1.点密度可视化2.直方图3. Voronoi图总结前言 ❤️❤️希望大家能多多点赞。❤️❤️ 需要数据集的可以评论。 Geoplotlib 是地理空间数据可视化的开源Python库,包含了大量的地理空间可视化操作&#xff0c…

131. 分割回文串

131. 分割回文串 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1: 输入:s “aab” 输出:[[“a”,“a”,“b”]…

青少年等级考试【Python通关干货】(二级)

青少年等级考试【Python通关干货】(二级)1.列表类型的概念 2.序列的通用操作 3.可变序列及列表的通用操作 4.列表的特有操作 5.元组类型的概念与操作