MySQL数据存储- 索引组织表
索引组织表
- 前言
- 数据存储
- 堆表
- 索引组织表
- 二级索引
- 二级索引的性能评估
- 🔹为什么 idx_name 的性能开销最大?
- 🔹 为什么 idx_last_modify_date 更新频繁会影响性能?
- 分析二级索引性能表格
- 为什么主键应该“紧凑且顺序”?
- 二级索引总结
- 堆表和索引组织表有什么区别,分别的应用场景是什么?
前言
InnoDB 存储引擎是 MySQL 数据库中使用最为广泛的引擎,在海量大并发的 OLTP 业务中,InnoDB 必选。这一章我们聊一聊 MySQL InnoDB 存储引擎的索引结构。
数据存储
数据存储有堆表和索引组织表两种方式.
堆表
堆表中的数据无序存放, 数据的排序完全依赖于索引.(Oracle、Microsoft SQL Server、PostgreSQL 早期默认支持的数据存储都是堆表结构)。
数据和索引分开存储。索引是排序后的数据,而堆表中的数据是无序的,索引的叶子节点存放了数据在堆表中的地址,当堆表的数据发生改变,且位置发生了变更,所有索引中的地址都要更新,这非常影响性能,特别是对于 OLTP 业务。
索引组织表
,数据根据主键排序存放在索引中,主键索引也叫聚集索引(Clustered Index)。在索引组织表中,数据即索引,索引即数据。
MySQL InnoDB 存储引擎就是这样的数据组织方式;Oracle、Microsoft SQL Server 后期也推出了支持索引组织表的存储方式。
数据按照主键的顺序存储在 B+ 树索引中,而不是采用传统的堆表(Heap Table)存储方式。这意味着:
- 数据是按主键排序存储的,不像普通表那样是无序的。
- 数据和索引存储在一起,不需要额外的索引来定位数据。
- 查询主键时更快,因为主键索引本身就包含数据。
表 User 的主键是 id,所以表中的数据根据 id 排序存储,叶子节点存放了表中完整的记录,可以看到表中的数据存放在索引中,即表就是索引,索引就是表。
二级索引
InnoDB 存储引擎的数据是根据主键索引排序存储的,除了主键索引外,其他的索引都称之为二级索引(Secondeary Index), 或非聚集索引(None Clustered Index)。
二级索引也是一颗 B+ 树索引,但它和主键索引不同的是叶子节点存放的是索引键值、主键值。
举个例子:
CREATE TABLE User (id BIGINT AUTO_INCREMENT,name VARCHAR(128) NOT NULL,sex CHAR(6) NOT NULL,registerDate DATETIME NOT NULL,...PRIMARY KEY(id), -- 主键索引KEY idx_name(name) -- 二级索引)
如果用户通过列 name 进行查询,比如下面的 SQL:
SELECT * FROM User WHERE name = 'David',
整个流程是:
通过二级索引 idx_name 只能定位主键值,需要额外再通过主键索引进行查询,才能得到最终的结果。**这种“二级索引通过主键索引进行再一次查询”的操作叫作“回表”,**你可以通过下图理解二级索引的查询:
二级索引的设计有个非常大的好处:
如果记录发生修改,其他索引无须进行维护,除非记录的主键发生修改.(因为二级索引存储的是主键,而不是数据的物理地址!)
举个例子:
UPDATE employees SET salary = salary * 1.1 WHERE emp_id = 1001;
salary 发生了变化,但 emp_id 没变,因此二级索引无需更新。
📌 索引组织表的二级索引维护情况总结
情况 | 是否需要更新二级索引? | 原因 |
---|---|---|
非主键字段更新(如 salary ) | ❌ 无需更新 | 二级索引指向主键,不受物理位置影响 |
数据物理位置变更 | ❌ 无需更新 | 物理存储位置变了,但主键没变 |
主键 emp_id 变更 | ✅ 需要更新 | 因为二级索引存的是主键值 |
删除记录 | ✅ 需要更新 | 需要删除二级索引中的主键引用 |
插入新记录 | ✅ 需要更新 | 需要在二级索引中添加新主键 |
👉 结论:索引组织表的二级索引维护成本低,除非主键变更,否则二级索引无需维护!
你会发现索引组织表在存在大量变更的场景下,性能优势会非常明显,因为大部分情况下都不需要维护其他二级索引。🚀
二级索引的性能评估
我们给出一个业务的表User:
CREATE TABLE User (id BINARY(16) NOT NULL,name VARCHAR(255) NOT NULL,sex CHAR(1) NOT NULL,password VARCHAR(1024) NOT NULL,money BIG INT NOT NULL DEFAULT 0,register_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),last_modify_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),uuid CHAR(36) AS (BIN_TO_UUID(id)),CHECK (sex = 'M' OR sex = 'F'),CHECK (IS_UUID(UUID)),PRIMARY KEY(id),UNIQUE KEY idx_name(name),KEY idx_register_date(register_date),KEY idx_last_modify_date(last_modify_date));
在 User 表中,有三个二级索引:
- idx_name(name)
- idx_register_date(register_date)
- idx_last_modify_date(last_modify_date)
🔹为什么 idx_name 的性能开销最大?
二级索引 idx_name 的数据是无序的,导致 B+ 树频繁分裂,影响性能。
🌟 解决方案:限制用户每天/每年可修改昵称的次数,减少 idx_name 的更新次数,从而减少二级索引的维护开销。
🔹 为什么 idx_last_modify_date 更新频繁会影响性能?
每次用户修改 money,都会导致 last_modify_date 更新,从而更新 idx_last_modify_date 索引。
🌟 解决方案:
业务层优化:如果某些操作不需要 last_modify_date 频繁更新,可以在业务代码中做条件判断,避免无意义的更新。
批量更新:对于高并发写入场景,可以考虑 定时批量更新 last_modify_date,而不是每次更新 money 都更新时间戳。
分析二级索引性能表格
二级索引的 插入性能 主要受 插入数据的顺序性 影响,插入是否有序决定了 索引的维护成本。
📌 索引的维护成本分析
索引 | 插入成本 | 更新成本 | 维护成本原因 |
---|---|---|---|
PRIMARY KEY (id) | ✅ 低 | ✅ 低 | 主键索引是顺序插入,且不会发生更新(除非主键变更)。 |
idx_name(name) | ❌ 高 | ❌ 高 | 随机插入,导致 B+ 树频繁分裂,影响插入性能;用户可修改昵称,更新时需要维护索引。 |
idx_register_date(register_date) | ✅ 低 | ✅ 低 | 顺序插入,不会更新,因此维护成本较低。 |
idx_last_modify_date(last_modify_date) | ✅ 低 | ❌ 高 | 顺序插入但更新频繁,每次用户数据变更都会触发索引更新,影响性能。 |
为什么主键应该“紧凑且顺序”?
主键的设计影响索引的存储和查询性能。
在 InnoDB 引擎下:
- 索引组织表 使用 B+ 树存储数据,主键决定了数据的存储顺序。
- 所有二级索引都会存储主键值,查询时先在二级索引查找,再回表通过主键找到完整数据。
因此:
- 主键应该尽量顺序(如自增 ID、顺序 UUID)
- 这样数据插入是 顺序填充 B+ 树,不会造成索引频繁分裂,提高插入性能。
- 主键应该尽量紧凑(占用字节少)
- 二级索引存储的是“索引列 + 主键”,如果主键太大(如 36 字节的 UUID),会导致索引数据量变大,影响查询性能。
🌟 解决方案: - 推荐使用 16 字节的顺序 UUID(BINARY(16)),而不是 36 字节的字符串 UUID(CHAR(36))。
- 如果可以,使用自增 ID(BIGINT)作为主键,查询效率最高。
二级索引总结
优化点 | 建议 |
---|---|
二级索引插入性能 | 避免创建随机插入的索引(如 idx_name ),如果必须使用,尽量限制更新频率。 |
二级索引更新开销 | 频繁更新的字段(如 last_modify_date )的索引可能影响性能,可以减少无意义的更新或批量更新。 |
主键设计 | 主键应该尽量紧凑(如 BINARY(16) 的顺序 UUID),避免使用大字段(如 CHAR(36) 的 UUID)。 |
索引顺序性 | 选择顺序性高的字段作为索引,提高索引插入效率,如 register_date 。 |
📌 结论
- 尽量使用顺序插入的索引(如
register_date
),避免随机插入的索引(如name
)。 - 减少不必要的索引更新,如
last_modify_date
,可以通过业务优化降低更新频率。 - 主键设计要紧凑且顺序,这样可以减少二级索引的存储和查询开销,提高整体性能。 🚀
堆表和索引组织表有什么区别,分别的应用场景是什么?
堆表(Heap Table)数据无序存储,是MyISAM使用的存储方式.主键索引存的是数据的物理地址,查询时需要回表获取完整数据.
因为所有索引都是平级,增删改性能较好.
但是查询需要回表,所以查询较慢,查询没有索引组织表好,且由于只支持行锁,适用于低并发场景,
索引组织表(IOT)数据按主键顺序存储,是InnoDB使用的存储方式.
主键索引的叶子节点直接存整行数据,主键查询不需要回表,但插入性能较低.
不过高并发场景下性能远高于堆表方式,适用于CRUD比较多的高并发场景(包括OLTP业务).
相关文章:

MySQL数据存储- 索引组织表
索引组织表 前言数据存储堆表索引组织表 二级索引二级索引的性能评估🔹为什么 idx_name 的性能开销最大?🔹 为什么 idx_last_modify_date 更新频繁会影响性能?分析二级索引性能表格为什么主键应该“紧凑且顺序”?二级索…...

基于STM32设计的仓库环境监测与预警系统
目录 项目开发背景设计实现的功能项目硬件模块组成设计思路系统功能总结使用的模块的技术详情介绍总结 1. 项目开发背景 随着工业化和现代化的进程,尤其是在制造业、食品业、医药业等行业,仓库环境的监控和管理成为了至关重要的一环。尤其是在存储易腐…...

VSCode便捷开发
一、常用插件 Vue 3 Snippets、Vetur、Vue - Official 二、常用开发者工具 三、Vue中使用Element-UI 安装步骤: 1、在VSCode的终端执行如下指令: npm i element-ui -S 2、在main.js中全局引入: import Vue from vue; import ElementUI from …...
理解 Maven 的 pom.xml 文件
pom.xml 是 Maven 项目的核心文件,它是项目构建、依赖管理、插件配置和项目元数据的主要地方。通过 pom.xml 文件,Maven 知道如何构建项目、下载依赖库、执行测试等任务。每个 Maven 项目都必须包含一个 pom.xml 文件。本文将详细讲解 pom.xml 文件的结构…...
docker数据持久化的意义
Docker 数据持久化是指在 Docker 容器中保存的数据不会因为容器的停止、删除或重启而丢失。Docker 容器本身是临时性的,默认情况下,容器内的文件系统是临时的,容器停止或删除后,其中的数据也会随之丢失。为了确保重要数据…...

opentelemetry-collector 配置elasticsearch
一、修改otelcol-config.yaml receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318 exporters:debug:verbosity: detailedotlp/jaeger: # Jaeger supports OTLP directlyendpoint: 192.168.31.161:4317tls:insecure: trueotlphttp/prometheus: …...
ASP.NET Core JWT Version
目录 JWT缺点 方案 实现 Program.cs IdentityHelper.cs Controller NotCheckJWTVersionAttribute.cs JWTVersionCheckkFilter.cs 优化 JWT缺点 到期前,令牌无法被提前撤回。什么情况下需要撤回?用户被删除了、禁用了;令牌被盗用了&…...

【ArcGIS】R语言空间分析、模拟预测与可视化技术
R语言在空间数据挖掘中具有广泛的应用,以下是一些关键内容和常用包的介绍: R语言空间数据挖掘的关键技术 空间数据类型 矢量数据:包括点(Point)、线(Line)、面(Polygon)等…...

日常知识点之面试后反思遗留问题汇总
梳理一下最近接触到的几个知识点: 1:突然问到端口复用 (SO_REUSEADDR) 端口复用一般用在服务端重启时,套接字处于time_wait状态时,无法绑定该端口,导致无法启动问题。 设置端口复用ÿ…...

链表(LinkedList) 1
上期内容我们讲述了顺序表,知道了顺序表的底层是一段连续的空间进行存储(数组),在插入元素或者删除元素需要将顺序表中的元素整体移动,时间复杂度是O(n),效率比较低。因此,在Java的集合结构中又引入了链表来解决这一问…...

Qt:Qt Creator项目创建
目录 认识Qt Creator Qt Creator概览 使用Qt Creator新建项目 选择项目模板 选择项目路径 选择构建系统 填写类信息设置界面 选择语言和翻译文件 选择Qt套件 选择版本控制系统 最终效果 认识Qt Creator Qt Creator概览 从开始菜单或者快捷方式打开Qt Creator集成开…...
windows11上,使用pipx安装Poetry,Poetry的安装路径是什么?
当使用 pipx 安装 Poetry 时,pipx 会将 Poetry 安装到一个独立的虚拟环境中,并将其可执行文件链接到一个集中的目录中。以下是 pipx 安装 Poetry 时的路径信息: 1. Poetry 的安装路径 pipx 会为每个工具(如 Poetry)创…...

详解状态模式
引言 水有固态、液态、气态三种状态,在不同条件下这三种状态可以相互转化。同样在软件设计中,有些对象也有不同的状态,不同状态的行为不同,状态模式就是用来处理这种情况的。 1.概念 状态模式(State Pattern):允许一个…...
能否通过蓝牙建立TCP/IP连接来传输数据
前言: 最近在做一个项目时,产生了一个疑问:能否通过蓝牙建立TCP/IP连接来传输数据 查阅了一些文章,可以得出结论:不行 下面是我截取的两篇个人认可的文章的回答: 文章一: 蓝牙是一种短距离无…...
uniapp mqttjs 小程序开发
在UniApp中集成MQTT.js开发微信小程序时,需注意平台差异、协议兼容性及消息处理等问题。以下是关键步骤与注意事项的综合指南: 一、环境配置与依赖安装 安装MQTT.js 推荐使用兼容性较好的版本:mqtt4.1.0(H5和小程序兼容性最佳&…...

爬虫工程师分享:获取京东商品详情SKU数据的技术难点与攻破方法
在电商数据领域,京东商品详情页的SKU数据是许多爬虫工程师的目标。这些数据包含了商品的价格、库存、规格等关键信息,对于市场分析、价格监控等应用场景至关重要。然而,获取这些数据并非易事,京东作为国内电商巨头,其反…...

数据库操作与数据管理——Rust 与 SQLite 的集成
第六章:数据库操作与数据管理 第一节:Rust 与 SQLite 的集成 在本节中,我们将深入探讨如何在 Rust 中使用 SQLite 数据库,涵盖从基本的 CRUD 操作到事务处理、数据模型的构建、性能优化以及安全性考虑等方面。SQLite 是一个轻量…...

LeetCode 0063.不同路径 II:动态规划 - 原地使用地图数组,几乎无额外空间开销
【LetMeFly】63.不同路径 II:动态规划 - 原地使用地图数组,几乎无额外空间开销 力扣题目链接:https://leetcode.cn/problems/unique-paths-ii/ 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0]&#…...

elementui:el-table支持搜索、切换分页多选功能,以及数据回显
1、el-table相关代码,需注意:row-key"(row) > { return row.id }" 以及 :reserve-selection"true" <div class"boxList"><div class"search-form"><!-- 搜索表单 --><el-form :inline"true&q…...
深度整理总结MySQL——索引正确使用姿势
索引正确使用姿势 前言MySQL索引优缺点分析✅ 索引的优势⚠️ 索引的代价 如何合理建立索引?——关键原则总结重要的优化机制索引覆盖——通俗的方式讲解索引下推索引跳跃式扫描 前言 这篇文章是补充一些基本概念和实战的一些使用建议. MySQL索引优缺点分析 ✅ 索引的优势 …...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...