MySql Innodb 索引有哪些与详解

概述

对于MYSQL的INNODB存储引擎的索引,大家是不陌生的,都能想到是 B+树结构,可以加速SQL查询。但对于B+树索引,它到底“长”得什么样子,它具体如何由一个个字节构成的,这些的基础知识鲜有人深究。本篇文章从MYSQL行记录开始说起,层层递进,包括数据页,B+树聚簇索引,B+树二级索引,最后在文章末尾给出MYSQL索引的建议。

表空间

首先,我们来了解一下 MySQL 的表空间。在 MySQL 中,所有的数据都被存储在一个空间内,称之为表空间,表空间内部又可以分为段(segment)、区(extent)、页(page)、行(row),其逻辑结构如下图:

段(segment)

表空间是由不同的段组成的,常见的段有:数据段,索引段,回滚段等等,在 MySQL 中,数据是按照 B+ 树来存储,因此数据即索引,因此数据段即为 B+ 树的叶子节点,索引段为 B+ 树的非叶子节点,回滚段用于存储undo日志,用于事务失败后数据回滚以及在事务未提交之前通过undo日志获取之前版本的数据,在 InnoDB 1.1 版本之前,一个 InnoDB 只支持一个回滚段,支持 1023 个并发修改事务同时进行,在 InnoDB 1.2 版本,将回滚段数量提高到了 128 个,也就是说可以同时进行128 * 1023个并发修改事务。

区(extent)

区是由连续页组成的空间,每个区的固定大小为 1MB,为保证区中页的连续性,InnoDB 会一次从磁盘中申请 4 ~ 5 个区,在默认不压缩的情况下,一个区可以容纳 64 个连续的页。但是在开始新建表的时候,空表的默认大小为 96KB,是由于为了高效的利用磁盘空间,在开始插入数据时表会先利用 32 个页大小的碎片页来存储数据,当这些碎片使用完后,表大小才会按照 MB 倍数来增加。

页(page)

页是 InnoDB 存储引擎的最小管理单位,每页大小默认是 16KB,从 InnoDB 1.2.x 版本开始,可以利用innodb_page_size来改变页大小,但是改变只能在初始化 InnoDB 实例前进行修改,之后便无法进行修改,除非mysqldump导出创建新库,常见的页类型有:数据页、undo页、系统页、事务数据页、插入缓冲位图页、插入缓冲空闲列表页、未压缩的二进制大对象页以及压缩的二进制大对象页等。

行(row)

行对应的是表中的行记录,每页存储最多的行记录也是有硬性规定的最多16KB/2-200,即 7992 行,其中 16KB 是页大小。

Clustered Index 聚簇索引

MySQL InnoDB 引擎具有强制聚簇索引,通常使用主键。也就是主键就是Clustered Index,如果没有主键按以下规则生成。

Clustered Index 条件优化级:
  1. 表有明确的PRIMARY KEY:使用PRIMARY KEY

  2. 无PRIMARY KEY:InnoDB 默认使用第一个 UNIQUE INDEX,且索引列需要全部定义为非空列(NOT NULL)作为Clustered Index

  3. 如无PRIMARY KEY,也没有合适的UNIQUE INDEX,InnoDB将会在包含行ROW ID的合成列上生成一个名为GEN_CLUST_INDEX的隐藏Clustered Index

ROW ID:ROW ID是6 byte字段,由InnoDB分配,用于行排序。插入新行而单调增加,在物理上插入按ROW ID顺序排列

注:UNIQUE INDEX 包含的列需要全部定义为NOT NULL非空,才会被当做Clustered Index

MyISAM 存储引擎不支持聚簇索引并且一直使用堆表

2. 聚簇索引如何加速查询

通过聚簇索引访问行很快,因为索引搜索直接指向包含行数据的页面。如果表很大,与使用与索引记录不同的页来存储行数据的存储组织相比,聚簇索引架构通常可以节省磁盘 I/O 操作。

3. Clustered Index 示例及查询:

INNODB_INDEXES 表type字段说明:

  • 0 = 非唯一索引的二级索引 :nonunique secondary index;

  • 1 = 自动生成的聚簇索引:automatically generated clustered index (GEN_CLUST_INDEX);

  • 2 = 唯一索引(非聚簇索引): unique nonclustered index;

  • 3 = 聚簇索引 clustered index;

  • 32 = 全文索引 full-text index

不同MySQL版本表名不同,使用命令查询:SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_%';

自动生成名为GEN_CLUST_INDEX的Clustered Index示例:

-- 创建无主键、无唯一索引 
CREATE TABLE `clustered_index_demo` (`id` int DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;-- 查询表索引 
-- 如5.7以下版本表名不同,使用命令查询:SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_SYS%';
SELECT t2.INDEX_ID ,t2.`NAME` , t2.TABLE_ID , t2.`TYPE` , t2.N_FIELDS , t2.PAGE_NO , t2.`SPACE` , t2.MERGE_THRESHOLD
FROM information_schema.INNODB_TABLES t1 
INNER JOIN information_schema.INNODB_INDEXES t2 ON t1.TABLE_ID = t2.TABLE_ID
WHERE t1.`NAME` = 'wiki/clustered_index_demo';-- 查询结果| INDEX_ID | NAME            | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|-----------------|----------|------|----------|---------|-------|-----------------|
|     3616 | GEN_CLUST_INDEX |     3276 |    1 |        5 |       4 |  2113 |  
增加包含NOT NULL列的唯一索引示例:

Tips : 修改表结构,InnoDB将删除原自动生成的GEN_CLUST_INDEX索引

-- 增加两列
ALTER TABLE `wiki`.`clustered_index_demo`
ADD COLUMN `username` varchar(32) NOT NULL,
ADD COLUMN `name` varchar(64) NOT NULL;
-- 增加唯一索引 
ALTER TABLE `wiki`.`clustered_index_demo`
ADD UNIQUE INDEX `IDX_UNIQUE` (`username`,`name`) USING BTREE;| INDEX_ID | NAME       | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|------------|----------|------|----------|---------|-------|-----------------|
|     3620 | IDX_UNIQUE |     3278 |    3 |        5 |       4 |  2115 |              50 |
唯一索引包含NULL列
-- 将唯一索引,其中一列改为NULL, Clustered Index将被删除,重新生成GEN_CLUST_INDEX
ALTER TABLE `wiki`.`clustered_index_demo`
CHANGE `username` `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
CHANGE `name` `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;| INDEX_ID | NAME            | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|-----------------|----------|------|----------|---------|-------|-----------------|
|     3625 | GEN_CLUST_INDEX |     3281 |    1 |        6 |       4 |  2118 |              50 |
|     3626 | IDX_UNIQUE      |     3281 |    2 |        3 |       5 |  2118 |      

查询所有自动生成的Clustered Index

SELECTi.TABLE_ID,t.NAME
FROMinformation_schema.INNODB_INDEXES iJOIN information_schema.INNODB_TABLES t ON (i.TABLE_ID = t.TABLE_ID)
WHEREi.NAME = 'GEN_CLUST_INDEX';| TABLE_ID | NAME                      |
|----------|---------------------------|
|     3281 | wiki/clustered_index_demo |

 辅助索引

除了聚簇索引之外的索引都可以称之为辅助索引,与聚簇索引的区别在于辅助索引的叶子节点中存放的是主键的键值。一张表可以存在多个辅助索引,但是只能有一个聚簇索引,通过辅助索引来查找对应的航记录的话,需要进行两步,第一步通过辅助索引来确定对应的主键,第二步通过相应的主键值在聚簇索引中查询到对应的行记录,也就是进行两次 B+ 树搜索。相反,通过辅助索引来查询主键的话,遍历一次辅助索引就可以确定主键了,也就是所谓的索引覆盖,不用回表。

创建辅助索引,可以创建单列的索引,也就是用一个字段来创建索引,也可以用多个字段来创建副主索引称为联合索引,创建联合索引后,B+ 树的节点存储的键值数量不是 一个,而是多个,如下图:

  • 联合索引的 B+ 树和单键辅助索引的 B+ 树是一样的,键值都是排序的,通过叶子节点可以逻辑顺序的读出所有的数据,比如上图所存储的数据时,按照(a,b)这种形式(1,1),(1,2),(2,1),(2,4),(3,1),(3,2)进行存放,这样有个好处,那就是存放数据时排序了,当进行order by对某个字段进行排序时,可以减少复杂度,加速进行查询;

  • 当用select * from table where a=? and ?可以使用索引(a,b)来加速查询,但是在查询时有一个原则,SQL 的where条件的顺序必须和二级索引一致,而且还遵循索引最左原则,select * from table where b=?则无法利用(a,b)索引来加速查询。

  • 辅助索引还有一个概念便是索引覆盖,索引覆盖的一个好处便是辅助索引不包含行记录,因此其大小远远小于聚簇索引,利用辅助索引进行查询可以减少大量的 IO 操作。

索引的优缺点及建议

 

优点:

  1. 对于等值查询,可快速定位到对于的行记录。

  2. 对于范围查询,可辅助缩小扫描区间。

  3. 当ORDER BY的列名 与 索引的列名完全一致时,可加快排序的顺序。

  4. 当GROUP BY的列名 与 索引的列名完全一致时,可加快分组。

  5. 当二级索引列中 包含了 SELECT 关键字后面写明的所有列,则在查询完成二级索引之后无需进行回表操作,直接返回即可。这种情况,称为【覆盖索引】。

缺点:

建立索引占用磁盘空间。

对表中的数据进行 增加,删除,修改 操作时,都需要修改各个索引树,特别是如果新增的行记录的主键顺序不是递增的,就会产生页分裂,页回收等操作,有较大的时间成本。

当二级索引列的值 的 不重复值的个数较少时,通过二级索引查询找到的数据量就会比较多,相应的就会产生过多的回表操作。

在执行查询语句的时候,首先要生成一个执行计划。通常情况下,一个SQL在执行过程中最多使用一个二级索引,在生成执行计划时需要计算使用不同索引执行查询时所需的成本,最后选择成本最低的那个索引执行查询。因此,如果建立太多的索引,就会导致成本分析过程耗时太多,从而影响查询语句的性能。

建议:

  1. 只为用于搜索,排序,分组的列创建索引。

  2. 索引的列需要有辨识性,尽可能地区分出不同的记录。

  3. 索引列的类型尽量小。因为数据类型越小,索引占用的存储空间就越少,在一个数据页内就可以存放更多的记录,磁盘I/O带来的性能损耗也就越小。

  4. 如果需要对很长的字段进行快速查询,可考虑为列前缀建立索引。【alter table table_M add index idx_key1(column_n(10)) -->  将table_M表的 idx_key1列的前10个字符创建索引】

  5. 覆盖索引,当二级索引列中包含了SELECT关键字后面写明的所有列,则在查询完成二级索引之后无需进行回表操作,直接返回即可。因此,编写【select *】的时候,要想想是否必要

  6. 在查询语句中,索引列不要参与条件值计算,也是把条件值计算完成之后,再和索引列对比。【否则MYSQL会认为搜索条件不能形成合适的扫描区间来减少扫描的记录数量】

 

 

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

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

相关文章

俄罗斯ozon运费计算工具,跨境电商ozon物流运费计算工具

OZON平台服装类目卖家而言,如何快速、准确地为产品定价,并有效管理运费成本,直接关系到市场竞争力与利润空间。接下来我们看看俄罗斯ozon运费计算工具,跨境电商ozon物流运费计算工具。 萌啦Ozon定价工具:智能模拟&…

你想活出怎样的人生?

hi~好久不见,距离上次发文隔了有段时间了,这段时间,我是裸辞去感受了一下前端市场的水深火热,那么这次咱们不聊技术,就说一说最近这段时间的经历和一些感触吧。 先说一下自己的个人情况,目前做前端四年&am…

day62--若依框架(基础应用篇)

若依搭建 若依版本 官方 若依官方针对不同开发需求提供了多个版本的框架,每个版本都有其独特的特点和适用场景: 前后端混合版本:RuoYi结合了SpringBoot和Bootstrap的前端开发框架,适合快速构建传统的Web应用程序,其…

Unity Shader 软粒子

Unity Shader 软粒子 前言项目Shader连连看项目渲染管线设置 鸣谢 前言 当场景有点单调的时候,就需要一些粒子点缀,此时软粒子就可以发挥作用了。 使用软粒子与未使用软粒子对比图 项目 Shader连连看 这里插播一点,可以用Vertex Color与…

XML简介XML 使用教程XML的基本结构XML的使用场景

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……) 2、学会Oracle数据库入门到入土用法(创作中……) 3、手把手教你开发炫酷的vbs脚本制作(完善中……) 4、牛逼哄哄的 IDEA编程利器技巧(编写中……) 5、面经吐血整理的 面试技…

汽车IVI中控开发入门及进阶(三十三):i.MX linux开发之开发板

前言: 大部分物料/芯片,不管MCU 还是SoC,都会有原厂提供配套开发板,有这样一个使用原型,在遇到问题时或者进行开发时可以使用。 i.MX 8QuadXPlus MEK board: 1、要测试display显示器,可使用i.MX mini SAS将“LVDS1_CH0”端口连接到LVDS到HDMI适配器的cable。 2、要测试…

微服务部署上线过程总结

目录 一、找到适合自己的部署方式 二、开始部署,先安装需要的环境 2.1 梳理一下都需要安装什么软件 2.2 配置数据库环境 2.3 配置redis 2.4 配置nacos 2.5 配置rabbitmq 2.6 配置docker环境 三、环境配置好了,开始部署后端 3.1 梳理后端都…

仓库管理系统12--供应商设置

1、添加供应商窗体 2、布局控件UI <UserControl x:Class"West.StoreMgr.View.SupplierView"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc"http://…

使用python做飞机大战

代码地址: 点击跳转

【论文阅读】伸缩密度比估计:Telescoping Density-Ratio Estimation

文章目录 一、文章概览&#xff08;一&#xff09;问题提出&#xff08;二&#xff09;文章工作 二、判别比估计和密度鸿沟问题三、伸缩密度比估计&#xff08;一&#xff09;核心思想&#xff08;二&#xff09;路标创建&#xff08;三&#xff09;桥梁构建&#xff08;四&…

Linux 生产消费者模型

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux初窥门径⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 前言 1. 生产消费者模型 1.1 什么是生产消…

每日一题——Python实现PAT乙级1005 继续(3n+1)猜想(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码逻辑概述 时间复杂度分析 空间复杂度分析 总结 我要更强 代码优化点…

Nginx详解-安装配置等

目录 一、引言 1.1 代理问题 1.2 负载均衡问题 1.3 资源优化 1.4 Nginx处理 二、Nginx概述 三、Nginx的安装 3.1 安装Nginx 3.2 Nginx的配置文件 四、Nginx的反向代理【重点】 4.1 正向代理和反向代理介绍 4.2 基于Nginx实现反向代理 4.3 关于Nginx的location路径…

Jetson系列机载电脑创建热点模式配置方法

Jetson nano为例—— 创建热点模式配置方法 1.1、新建一个 WiFi 在屏幕右上角找到网络图标&#xff0c;点击后选择“Edit Connections”选项&#xff0c;进入选择网络连接页面&#xff0c;然后点击左下角加号&#xff0c;新建一个连接&#xff0c;类型选择 WiFi 后点击 “cre…

如何选择适合自己的巴比达内网穿透方案

选择适合自己的巴比达内网穿透方案&#xff0c;需要考虑几个关键因素&#xff0c;包括您的具体需求、安全性要求、技术水平以及预算。以下是一些选择巴比达内网穿透方案的建议步骤&#xff1a; 1. 确定需求和用途 首先&#xff0c;需要明确您希望通过内网穿透实现的具体目标和…

【linux学习---1】点亮一个LED---驱动一个GPIO

文章目录 1、原理图找对应引脚2、IO复用3、IO配置4、GPIO配置5、GPIO时钟使能6、总结 1、原理图找对应引脚 从上图 可以看出&#xff0c; 蜂鸣器 接到了 BEEP 上&#xff0c; BEEP 就是 GPIO5_IO05 2、IO复用 查找IMX6UL参考手册 和 STM32一样&#xff0c;如果某个 IO 要作为…

DP:解决路径问题

文章目录 二维DP模型如何解决路径问题有关路径问题的几个问题1.不同路径2.不同路径Ⅱ3.下降路径最小和4.珠宝的最高价值5.地下城游戏 总结 二维DP模型 二维动态规划&#xff08;DP&#xff09;模型是一种通过引入两个维度的状态和转移方程来解决复杂问题的技术。它在许多优化和…

使用VMware创建Ubuntu 24.04【一】

系列文章目录 第二章 使用Ubuntu安装Frappe-Bench【二】 文章目录 系列文章目录前言相关链接下载地址虚拟机创建与运行初始化系统中配置 前言 VMware是一个虚拟化软件&#xff0c;它允许用户在一台计算机上模拟多个虚拟计算机环境。通过使用VMware&#xff0c;用户可以轻松地…

【Python】已解决:AttributeError: ‘function’ object has no attribute ‘ELement’

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;AttributeError: ‘function’ object has no attribute ‘ELement’ 一、分析问题背景 在Python编程中&#xff0c;AttributeError通常表明你试图访问一个对象…

【Linux】生物信息学常用基本命令

wget网址用于直接从网上下载某个文件到服务器&#xff0c;当然也可以直接从网上先把东西下到本地然后用filezilla这个软件来传输到服务器上。 当遇到不会的命令时候&#xff0c;可以使用man “不会的命令”来查看这个命令的详细信息。比如我想要看看ls这个命令的详细用法&…