MyISAM 引擎和 InnoDB 引擎中索引存储的区别

news2024/10/5 3:31:46

一、MyISAM 引擎下的索引

MyISAM 存储引擎不支持行级锁,只有表级锁;不支持事务,也不支持外键,主要面向 OLAP 应用,是 MySQL 数据库5.5.8 版本之前默认的存储引擎,MyISAM 适用于不需要关心事务,读多写少的场景。

每张 MyISAM 表在磁盘上会创建三个文件:.frm,.MYD 和 .MYI,其中 .frm 文件为表结构文件,每个存储引擎都会有这个文件,.MYD 文件用来存储数据,.MYI 文件用来存储索引,也就是说 MyISAM 表的数据和索引是分开存储的,这一点和 InnoDB 不一样。

在 MySQL 5.0 之前,MyISAM 引擎默认支持的表只有 4GB,如果要修改默认表大小的话,需要修改参数 MAX_ROWS 和AVG_ROW_LENGTH 的大小,不过这一点在 MySQL5.0 之后得到了改善,默认大小为 256TB,这个大小在绝大部分应用应该都是可以满足要求的。

MyISAM 的 B+ 树里面,叶子节点存储的是当前索引的值以及当前数据文件对应的磁盘地址。所以如果从索引文件 .MYI 中找到键值后,会根据其存储的磁盘地址到数据文件 .MYD 中获取相应的数据记录,在 MyISAM 引擎中,主键索引和非主键索引没有差别,都是一样存储,查询速度也没有差别,MyISAM 索引大致结构如下图所示:
在这里插入图片描述

二、InnoDB 引擎下的索引

InnoDB 存储引擎支持事务,主要是为了面向在线事务处理(OLTP)的应用而生,支持行锁和外键,其通过使用多版本并发控制(MVCC)来提升高并发性能,实现了 SQL92 标准的 4 种隔离级别。

从 MySQL 数据库 5.5.8 版本开始,InnoDB 为 MySQL 默认存储引擎。每张 InnoDB 表在磁盘上会创建两个文件:.frm 和 .ibd,其中 .frm 文件和 MyISAM 引擎一样,用来存储表结构的,.ibd 文件存储的是索引和数据,InnoDB 中索引和数据放在同一个文件中。

在 InnoDB 引擎中的 B+ 树叶子节点直接存储的是整条数据记录,而不是记录磁盘地址。InnoDB 引擎和 MyISAM 引擎还有一个最大的不同就是 InnoDB 引擎是以主键索引来组织数据的(主键索引和非主键索引的存储结构是不同的),InnoDB 存储引擎中这种组织数据的方式被称之为索引组织表(index-organized table),其中的主键索引也被称之为聚集索引(clustered index)。

聚集索引

聚集索引(又称之为聚簇索引),聚集的术语表示的是索引键值和数据紧凑的存储在一起。而数据又不可能同时存在两个地方,所以 InnoDB 每张表都有且只有一个聚集索引。换言之,也就是说每张表都必须有且只有一个主键。说到这里可能很多人就要反问了,我建表的时候没有主键索引也可以建表成功,那么这又是为什么呢?

其实如果我们没有显示的指定主键,InnoDB 会选择一个非空的唯一索引列作为主键,如果我们也没有创建非空的唯一索引,那么 InnoDB 就会选择其自己内置的一个 6 字节长的 ROWID 自增列作为主键。InnoDB 中聚集索引叶子节点直接存储的是整条数据,也就是说索引搜索到叶子节点之后就可以直接返回数据了,无需再去磁盘获取数据。

InnoDB 中聚集索引大致结构如下图所示:
在这里插入图片描述
接下来我们来验证一下 rowid 是否存在
进入数据库之后,我们创建两张表,一张表带有主键索引,一张表只带了一个普通索引

CREATE TABLE `test_index` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `a` INT DEFAULT NULL,
  `b` INT DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `test_noIndex` (
  `id` int NOT NULL,
  `a` int DEFAULT NULL,
  `b` int DEFAULT NULL,
  KEY `a_index` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

建表之后,在上面的两张表中分别插入两条数据:

INSERT INTO `test_index` (`id`, `a`, `b`) VALUES('1','11','11');
INSERT INTO `test_index` (`id`, `a`, `b`) VALUES('2','22','22');

INSERT INTO `test_noIndex` (`id`, `a`, `b`) VALUES('1','11','11');
INSERT INTO `test_noIndex` (`id`, `a`, `b`) VALUES('2','22','22');

最后执行以下两句查询:

SELECT _rowid,id,a,b FROM test_index;
SELECT _rowid,id,a,b FROM test_noIndex;

可以看到,当我们存在主键索引时候,_rowid 就等于主键索引,而当不存在主键索引时,默认会采用其内置的算法,这个时候我们就无法直接查询
在这里插入图片描述

非聚集索引

除了主键索引之外的其他索引都是非聚集索引(Secondary Indexes),既然聚集索引的索引键值和数据行存放在一起,而聚集索引又只有一个,那么非聚集索引又是怎么存储数据的呢?

非聚集索引的叶子节点存储的是当前索引的键值和主键索引的键值。大致结构如下图所示(右边为非聚集索引,左边为聚集索引):
在这里插入图片描述
所以非聚集索引查询数据和聚集索引查询数据是不同的,因为非聚集索引的叶子节点只有当前索引的键值和主键的键值,也就是说查询数据的时候获取到非聚集索引的叶子节点只能拿到当前索引值和主键索引值。

回表

回表指的就是非聚集索引从叶子节点拿到数据(主键的键值)之后,还需要再根据主键键值去扫描主键索引的 B+ 树,这种操作就叫做回表。

三、为什么主键索引比其他索引快

上面提到的回表操作需要扫描两颗 B+ 树,这也就是为什么在 InnoDB 中主键索引的效率相比较其他索引是最高的,因为主键索引只需要扫描一棵 B+ 树。

下面我们来测试一下主键索引和非主键索引的速度。

首先创建一张表,这张表里面还有一个主键索引和一个普通索引:

CREATE TABLE `test_speed` (
  `id` int NOT NULL,
  `user_name` varchar(16) NOT NULL,
  `job` varchar(16) NOT NULL,
  `company` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_company` (`company`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后执行以下脚本,批量插入 100 万数据:

DROP PROCEDURE IF EXISTS proc1;
DELIMITER ;;
CREATE PROCEDURE proc1()
BEGIN
  DECLARE i INT;
  DECLARE company VARCHAR(128);
  SET i=1;
  WHILE(i<=250000) DO
    IF i%6 = 0
      THEN SET company= '证券';
    ELSEIF i%6 = 1
      THEN SET company= '银行';
    ELSEIF i%6 = 2
      THEN SET company= '保险';
    ELSEIF i%6 = 3
      THEN SET company= '科技';
    ELSEIF i%6 = 4
      THEN SET company= '金融';
    ELSE
      SET company ='传统';
    END IF;
    INSERT INTO test_speed VALUES(i, CONCAT('孤狼',i), CONCAT('程序员',i),company);
    SET i=i+1;
  END WHILE;
END;;
DELIMITER ;
CALL proc1();

因为一次性插入了 25 万数据,最后调用存储过程的时候会有点慢,大家可以耐心的等待一下,这里选择插入 25 万是为了对比的时候速度上能更直观的看出对比结果,数据量太少会导致对比不明显(25 万数据插入完成自测环境下是将近 10 分钟 )。

数据初始化完成之后,我们继续执行以下两句 sql 进行对比:

SELECT * FROM test_speed ORDER BY id LIMIT 240000,5;-- 使用主键索引(聚集索引)
SELECT * FROM test_speed ORDER BY company LIMIT 240000,5;-- 使用非主键索引(非聚集索引)

在这里插入图片描述从结果中,可以很明显的看到,使用主键索引相比较非主键索引,速度会更快。

覆盖索引

上面我们说到了回表操作,那么就还有这么一种场景是不需要回表的:比如说我们一个查询只需要查询当前索引的值和主键的值,而不需要查其他数据,这时候就不需要回表了,直接就可以返回,这种也称之为覆盖索引。

因为非聚集索引中存储了当前索引的值和主键的值,所以如果我们不需要获取当前索引值和主键索引值之外的其他信息,那么在拿到主键索引值之后就可以直接返回,也就是只需要扫描一棵非聚集索引的 B+ 树,而因为非聚集索引不存储数据,所以非聚集索引的 B+ 树占用的空间是小于主键索引 B+ 树的,所以查询速度会更快。

这也是为什么通常不建议写 select * 语句的原因,因为 select * 肯定无法用到覆盖索引(除非整张表的字段是一个联合索引),而覆盖索引可以少扫描一棵聚集索引的 B+ 树,而且因为辅助索引不会存储整条数据,所以大小也要远小于聚集索引的 B+ 树,故而对性能有较大的提升。

需要注意的是,MyISAM 引擎中如果查找的数据也包含在索引内,不需要去磁盘找数据,也可以认为是覆盖索引,但是一般情况下我们说的覆盖索引都是针对 InnoDB 引擎而言。

接下来我们再测试一下使用到覆盖索引和使用主键索引的查询速度对比:

SELECT * FROM test_speed ORDER BY id LIMIT 240000,5;-- 使用主键索引
SELECT id,company FROM test_speed ORDER BY company LIMIT 240000,5;-- 使用覆盖索引

这里的第二句话使用到了 company 字段上的索引,而 company 索引上存储了主键的值,所以当我们仅查询主键和当前使用索引的字段时,就可以直接使用到覆盖索引。

执行之后,对比结果如下图所示:
在这里插入图片描述
从结果也可以看到,使用覆盖索引的速度会比主键索引更快。当然,因为我们的测试数据相对比较简单,所以有时候数据量过少的话对比不会很明显。

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

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

相关文章

实时即未来,大数据项目车联网之原始数据实时ETL任务HBase调优【九】

1. 原始数据实时ETL任务HBase调优 1.1 数据写入hbase优化 上一节写入数据,一条条数据put到表中,对于大量数据的写入,效率极低,因此针对此项进行优化 使用hbase客户端写缓存进行批量写入数据到hbase中 hbase客户端写缓存对象:BufferedMutator hbase的每一次put操作写入数据…

CSS权威指南(二)选择符

1.样式的基本规则 CSS的一个核心优势就是可以为文档中某种种类的元素全部应用相同的样式规则。CSS样式便于修改和编辑&#xff0c;而且能应用到指定的所有文本元素上。 &#xff08;1&#xff09;元素选择符 即直接使用元素的名称进行选择&#xff0c;类似于p{ font-size:10px…

Lc.152 乘积最大子数组

题目链接1 前言翻译成大白话&#xff1a;就是找一个数组&#xff0c;其连续子数组的乘积最大值。2 算法思路&#xff1a;一般求最值的问题首选动态规划。这道题与[LC.53 最大子序和]很类似。我们假设状态转移方程为:它表示以第 i 个元素结尾乘积最大子数组的乘积可是在这里&…

异步通信技术AJAX | AJAX实现省市联动、AJAX跨域问题

目录 一&#xff1a;异步通信技术AJAX | 快速搞定AJAX&#xff08;第四篇&#xff09; 1、AJAX实现省市联动 2、超链接、form表单和JS代码跨域 3、AJAX跨域问题 &#xff08;1&#xff09;测试Ajax跨域访问 &#xff08;2&#xff09;同源 & 不同源 &#xff08;3&a…

可以通过哪些方式了解量化接口level2?

可以通过哪些方式了解量化接口level2&#xff1f;大家可以去百查看关于量化交易接口的信息&#xff0c;根据小编对市场上大多数的level2接口了解发现既有要收费的也有免费的&#xff0c;一般来说第三方软件公司提供的都是收费的居多&#xff0c;一些正规券商提供的就是免费的居…

一文读懂自动驾驶汽车:软硬结合 造就未来出行体验(下篇)

在上篇&#xff0c;我们回顾了自动驾驶汽车的发展历史&#xff0c;介绍了自动驾驶汽车的工作原理。得益于 AI 技术的突破&#xff0c;自动驾驶汽车飞速发展&#xff0c;运算速度也从 2007 年的 230 FLOPS 跃升至 2022 年的 254 TOPS&#xff0c;向软件定义汽车发展。现在&#…

数据结构-考研难点代码突破 (C++实现有向无环图的拓扑排序)

文章目录1. AOE网2. 拓扑排序C代码1. AOE网 AOV网∶若用DAG 图&#xff08;有向无环图&#xff09;表示一个工程&#xff0c;其顶点表示活动&#xff0c;用有向边<Vi&#xff0c;Vj>表示活动 Vi必须先于活动Vj进行的这样一种关系&#xff0c;则将这种有向图称为顶点表示…

基于主从博弈的智能小区代理商定价策略及电动汽车充电管理(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

C语言贪吃蛇大作战

C语言贪吃蛇大作战 贪吃蛇大作战 1997 年&#xff0c;诺基亚公司发布了贪吃蛇游戏&#xff0c;并将其内置于诺基亚 6110 手机中&#xff0c;使这款游戏迅速风靡全球&#xff0c;成为一代经典。一般的观点认为&#xff0c;贪吃蛇是手机游戏的鼻祖。 与传统单人贪吃蛇不同的是&…

【时间之外】系统管人,能行?(冷眼旁观连载之一)

目录 写作初心 在用工具 某微 某道 某书 工具痛点 某微痛点 某道痛点 某书痛点 总结一下&#xff1a;功能复杂 2023年观察计划 最大痛点 效果跟踪 未完待续 写作初心 2022年应该是这一生中值得纪念的一年&#xff0c;疫情封控自不必说&#xff0c;对于个人而言&a…

traefik gateway api

背景 在使用istio后开始考虑网关了&#xff0c;istio已经有自己的网关&#xff0c;为什么还要另外找一个别的网关&#xff0c;参考了好几个文章大致结论是&#xff0c;istio的网关功能不够强大&#xff0c;下图红色的部分是istio网关暂时缺失的&#xff0c;所以我的结论是在is…

Monorepo 下 Git 工作流的最佳实践

作者&#xff1a;林宜丙 背景 没有哪一种 Git 工作流是银弹&#xff0c;合适的 Git 工作流往往取决于项目的代码规模、协作人数、应用场景等&#xff1b;本次分享先从适合小型 Monorepo 的 Feature branch 工作流开始分享&#xff0c;接着分享适用于中大型 Monorepo 的 Trunk…

头歌:Ping客户端创建原始套接字(底部附全关完整答案)

头歌实践教学平台 (educoder.net)为Ping客户端创建一个原始类型的套接字原始套接字套接字&#xff08;socket&#xff09;是一个抽象层网络应用程序可以通过它发送或接收数据&#xff0c;可对其进行像文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中&a…

<C++>二叉树进阶

文章目录为什么要学这一节1. 二叉搜索树1.1 二叉搜索树概念1.2 二叉搜索树操作1.3 二叉搜索树的实现1.4 二叉搜索树的应用1.5 二叉搜索树的性能分析2. 经典题目2.1 最近公共祖先2.2 从前序与中序遍历序列构造二叉树2.3 二叉树的前序遍历&#xff08;非递归&#xff09;为什么要…

计算机组成原理复习:数据的表示和运算

计算机组成原理复习&#xff1a;数据的表示和运算2. 数据的表示和运算2.1 数制与编码2.1.1 数制&#xff1a;进位计数制及其相互转换2.1.2 编码&#xff1a;数值数据的编码与表示2.1.2.1 逻辑型数据2.1.2.2 字符型数据 之 ASCII码2.1.2.3 数值型数据 之 BCD码2.1.3 校验码——奇…

Part类 -- 上传文件

Part类 -- 上传文件一、核心方法1.1 HttpServletRequest 类方法1.2 Part 类方法二、代码示例前端搭配 form 表单&#xff1a;form input type “file”&#xff0c;允许通过浏览器选中一个文件上传给服务器。 Servlet 就支持处理这种上传文件的请求&#xff0c;把这个请求到的文…

安科瑞智能操控无线测温装置在江苏某化工产业园项目的应用

安科瑞 李亚俊 1 概述 江苏富强新材料有限公司是中国企业500强——山东金岭集团在江苏淮安盐化新材料产业园区投资设立的盐化工企业。公司将利用淮安丰富的盐矿资源和优越的发展环境&#xff0c;投资200亿元&#xff0c;建设120万吨/年离子膜烧碱项目、70万吨/年甲烷氯化物项…

vue新春游戏-拼手速抢车票小游戏,学习玩乐两不误,春节小游戏,新年小游戏

ue新春游戏-拼手速抢车票&#xff0c;老规矩&#xff0c;体验地址&#xff1a;http://game.pkec.net/word-ticket/。 写这个主要是前几天群里运营老师说咋没人写抢车票的&#xff0c;再加上我上一篇文章上了掘金一周&#xff0c;听说多上几次有证书&#xff0c;我还没搞到过掘金…

Go语言 函数传递:值传递 和 虚假的 “引用传递”

前言 其实从变量本身来说&#xff0c;go只有值传递&#xff0c;函数内的修改不会影响函数外。但有一种特例是指针&#xff0c;go可以传指针给函数&#xff0c;指针指向申请出来的实际内存&#xff0c;也就是保存元素的内存&#xff0c; 这样在函数内的修改&#xff0c;可以影响…

就算是TOP程序员,也有这些坏习惯

绝大多数程序员在职业生涯中&#xff0c;多多少少都会养成一些坏习惯&#xff0c;今天就来说一说身边最常见的一些坏习惯&#xff0c;也给刚入行的新朋友们提个醒&#xff0c;少走一些弯路。 那么&#xff0c;就让我们开始吧&#xff01; 1.不注意适当休息 比如日常工作时、…