MySQL索引实现原理分析

2023-10-29

       目前大部分数据库系统及文件系统都采用B-Tree(B树)或其变种B+Tree(B+树)作为索引结构。B+Tree是数据库系统实现索引的首选数据结构。在 MySQL 中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论 MyISAM 和 InnoDB 两个存储引擎的索引实现方式。

MyISAM 索引实现 

       MyISAM 是非聚集索引,索引和数据文件是分离的;使用 B+Tree 作为索引结构,,索引叶节点的 data 域存放的是数据记录的地址;主键索引和辅助索引是独立的。

主键索引

      这里设表一共有三列,假设我们以 Col1 为主键,则图是一个 MyISAM 表的主索引(Primary key)示意。可以看出 MyISAM 的索引文件叶节点仅仅保存数据记录的地址。
MySQL索引实现原理分析

辅助索引 

      在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求 key 是唯一的,而辅助索引的 key 可以重复。如果我们在 Col2 上建立一个辅助索引,则此索引的结构如下图所示。

       同样也是一颗 B+Tree,data 域保存数据记录的地址。因此,MyISAM 中索引检索的算法为首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其data 域的值,然后以 data 域的值为地址,读取相应数据记录。
MySQL索引实现原理分析

       
InnoDB 索引实现 

      虽然 InnoDB 也使用 B+Tree 作为索引结构,但具体实现方式却与 MyISAM 截然不同。

       1、第一个重大区别是 InnoDB 的数据文件本身就是索引文件。从上文知道,MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。

MySQL索引实现原理分析

      上图是 InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为 InnoDB 的数据文件本身要按主键聚集。

       2、InnoDB 要求表必须有主键(MyISAM 可以没有),如果没有显式指定,则 MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,类型为长整形。

        同时,请尽量在 InnoDB 上采用自增字段做表的主键。因为 InnoDB 数据文件本身是一棵B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。如下图所示:
MySQL索引实现原理分析

        这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很高,也不会增加很多开销在维护索引上。

        3、还有与 MyISAM 索引的不同是 InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址。换句话说,InnoDB 的所有辅助索引都引用主键作为 data 域。
       例如,下图为定义在 Col3 上的一个辅助索引:
MySQL索引实现原理分析
 

       聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引(回表):首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

 问:为什么不建议使用过长的字段作为主键?

 答:因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。


聚簇索引与非聚簇索引 

      InnoDB 使用的是聚簇索引, 将主键组织到一棵 B+树中, 而行数据就储存在叶子节点上, 若使用"where id = 14"这样的条件查找主键, 则按照 B+树的检索算法即可查找到对应的叶节点, 之后获得行数据。 若对 Name 列进行条件搜索, 则需要两个步骤:
      第一步在辅助索引 B+树中检索 Name, 到达其叶子节点获取对应的主键。
      第二步使用主键在主索引 B+树种再执行一次 B+树检索操作, 最终到达叶子节点即可获取整行数据。

       MyISM 使用的是非聚簇索引, 非聚簇索引的两棵 B+树看上去没什么不同, 节点的结构完全一致只是存储的内容不同而已, 主键索引 B+树的节点存储了主键, 辅助键索引B+树存储了辅助键。 表数据存储在独立的地方, 这两颗 B+树的叶子节点都使用一个地址指向真正的表数据, 对于表数据来说, 这两个键没有任何差别。 由于索引树是独立的, 通过辅助键检索无需访问主键的索引树。

       为了更形象说明这两种索引的区别, 我们假想一个表如下图存储了 3 行数据。 其中Id 作为主索引, Name 作为辅助索引。 图示清晰的显示了聚簇索引和非聚簇索引的差异:
MySQL索引实现原理分析

联合索引及最左原则

联合索引存储数据结构图:

最左原则:

例如联合索引有三个索引字段(A,B,C)

查询条件:

(A,,)--- 会使用索引

(A,B,)--- 会使用索引

(A,B,C)--- 会使用索引

(,B,C)--- 不会使用索引

(,,C)--- 不会使用索引

最后来一个问题:mysql假设一行数据大小为1k,则一颗层高为3的b+树可以存放多少条数据?

       mysql页默认大小16k,如果数据行大小1k,叶子节点存放的完整数据,则叶子节点一页可以放16条数据;非叶子节点页面存放的是主键和指针,所以主要看主键是啥类型,假设是integer,则长度8字节,指针大小在innodb是6字节,一共14字节,所以非叶子节点每页可以存16384/14=1170个主键数据(1170个分叉),则三层b+树数据可以存1170*1170*16=21902400条数据。(千万级别

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL索引实现原理分析 的相关文章

  • 我可以停止 CakePHP 获取查询的所有行吗?

    我正在使用 CakePHP 和 modelName gt find 调用选择相当多的行 可能是数百行 通常 在 PHP MySQL 中这当然不会成为问题 因为您在 while 循环中获取它们 但是 CakePHP 将所有行加载到一个数组中
  • MySQL:如果该ip没有任何记录则插入

    I use INSERT INTO rating name user rating section ip VALUES name SESSION user rate section SERVER REMOTE ADDR 我想在 IF 语句中
  • 解析 JSONException:JSONArray 文本必须以字符 1 处的 '[' 开头

    我正在尝试将 Android 应用程序与本地 MySQL 数据库连接 但遇到问题 解析 JSON 数组 我在这里阅读了所有类似的问题 但没有任何作用 错误消息 Error parsing data org json JSONExceptio
  • MySQL - 选择字符串的前 10 个字节

    各位聪明的男士女士们 大家好 如何选择字符串的前 x 个字节 用例 我正在优化产品描述文本以上传到亚马逊 亚马逊按 utf8 中的字节 不是我之前所说的 latin1 而不是字符来测量字段长度 另一方面 MySQL 似乎是基于字符进行操作的
  • MySQL 查询在基于特定标签组合获取行时返回不需要的行

    我在 Windows 8 PC 上运行 PHP MySQL 我有一张桌子mytable像下面这样 product tag lot 1111 101 2 1111 102 5 2222 103 6 3333 104 2 4444 101 2
  • 在学说监听器中插入元素

    我已经设置了一个学说监听器 它在不同的数据库操作上触发并创建一个日志实体并将其插入数据库 class FOO public function onFlush OnFlushEventArgs args foreach args gt get
  • DataImportHandler 未在 solr admin 中索引 mysql 表

    我正在尝试使用 DataImportHandler 在 solr 中索引 mysql 表 但它似乎没有索引 数据配置 xml
  • mysql JOIN,这是如何解释的?

    如果我为 mysql 编写一条 sql 查询 并且只指定 JOIN 没有外连接 内连接 左连接等 那么默认的连接类型是什么 例如 SELECT count FROM Students p JOIN 班级 c ON p studentId c
  • 用户已拥有超过“max_user_connections”个活动连接 HANGFIRE

    我明白 用户已拥有超过 max user connections 个活动连接 已经有很多答案了 但这是关于Hangfire的 我在用Hangfire http docs hangfire io en latest background pr
  • FIND_IN_SET() 与 IN()

    我的数据库中有 2 个表 一种是针对订单的 一种是针对公司的 订单具有以下结构 OrderID attachedCompanyIDs 1 1 2 3 2 2 4 公司的结构如下 CompanyID name 1 Company 1 2 An
  • 如何在我的网站中创建全局搜索[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何在我的网站中创建全局搜索 该网站是内部网站 无法在网上使用 我无法使用 Google 搜索来实现此目的 我的信息全部存储在不同的
  • 数组在浏览器中给出 null 作为输出

    我测试了我的 Java 程序是否正确从 MySQL 检索数据 然而 问题出在Java和JSP之间 JSP页面无法从java程序中检索数据 请帮助我 它给出的输出为空 null null hai 我的jsp页面 div style heigh
  • 如何调试没有错误消息的错误?

    如何调试没有错误消息的错误 当加载 PHP 页面时 我在 Firefox 中收到此错误 The connection to the server was reset while the page was loading 除了看起来是 Apa
  • 如何选择非“唯一”行

    我有下表 我必须从中获取非唯一行 id idA infos 0 201 1899 1 205 1955 2 207 1955 3 201 1959 我想获取该列的所有行infos 具有相同的idA至少有两行的值 上表的查询输出必须是 inf
  • 在 PHP MySQL 中使用 jQuery AJAX 提交表单而无需重新加载

    我有一个基本的注册 登录页面 它使用 php 将数据提交到 SQL 数据库 但是 我希望页面在 jQuery AJAX 的帮助下不要在提交时重定向 无论成功与否 这是我目前所拥有的 但不起作用 它不显示任何错误消息 HTML 注册 html
  • Laravel 查询生成器 - 高级条件子句(可选参数)

    我需要带有接受可选参数的查询生成器的子句 例如 请考虑以下情况 我们有三个搜索字段 产品标题 公司名称和位置 邮政编码 城市或州 2 3 8 种可能性 该位置与 OR 连接 WHERE location postal code LIKE O
  • 如何使用mysqli准备好的语句?

    我正在尝试准备好的语句 但下面的代码不起作用 我收到错误 致命错误 在非对象上调用成员函数execute var www prepared php 第 12 行
  • 无法使用php连接到远程数据库

    我在 Windows 中安装了 Xampp 并且正在使用 Laravel 5 3 创建一个应用程序 我正在尝试在本地网络上的另一台服务器上执行查询 但是当我尝试这样做时 MySql 服务器使用以下命令对本地服务器上的用户进行身份验证 use
  • 如何通过csv文件仅更新sql表的一列

    我有一个 csv 文件包含一些数据 在我的 Sql 数据库中 我有一个具有多个列名的表 现在我只想通过 csv 文件更新一列 谢谢 你可以这样尝试 Import the csv file to a temp table Update you
  • SQL Server 与 MySQL:CONTAINS(*,'FORMSOF(THESAURUS,word)')

    我很震惊 当我在 SQL Server 中看到查询非常简单时 我花了 3 4 天弄清楚如何在 mysql 中实现词干提取 和同义词搜索 Select from tab where CONTAINS FORMSOF THESAURUS wor

随机推荐

  • python的launcher用法知识点总结

    更多编程教程请到 菜鸟教程 https www piaodoo com python launcher是适用于 Windows 的 Python 启动器 可帮助您定位和执行不同的 Python 版本 它允许脚本 或命令行 为特定的 Pyth
  • Idea 生成模板代码(Demo)

    1 在html文件中复制需要生成模板的代码 如下图选中部分 ctrl c 2 点击 File gt Settings 如下图 3 选择 Editor gt Live Template 点击右边的 然后点击 1 Live Template 如
  • 【Yarn】Yarn ApplicationMasterLauncher的工作机制

    文章目录 1 概述 2 源码 2 1 类变量 2 2 构造方法 2 4 serviceInit 2 5 serviceStart 2 6 LauncherThread 2 7 launch事件 2 8 AMLauncher的run 1 概述
  • 前端框架Vue(5)——Vue + Echarts (数据可视化)

    Echarts 是数据可视化中佼佼者 推荐大家可以玩一玩 非常实用 如果第一次接触Echarts的同学 这边有我以前写过的一篇入门 浅谈Echarts3 0 Vue Echarts 现附上代码
  • 数据结构作业:实现链表的基本操作

    数据结构作业 实现链表的基本操作 链表是一种常见的数据结构 它由一系列节点组成 每个节点包含数据和指向下一个节点的指针 本文将介绍链表的基本操作 包括创建链表 插入节点 删除节点以及遍历链表 首先 我们需要定义链表节点的结构体 节点包含一个
  • signature=31a231fa44057e3d64bcbe8f86676d0e,typescript-definitions

    THIS IS AN AUTOGENERATED FILE DO NOT EDIT THIS FILE DIRECTLY yarn lockfile v1 continuous auth client 1 1 0 version 1 2 3
  • 2020-04-08

    查看有关计算机的基本信息 1 右键点击 计算机 的 属性 就能看到这台电脑的基本信息了
  • Android Platform 3.0 SDK和Eclipse ADT安装记录(最初版本,纪念用)

    注意 此文非常非常地过时 只是用于个人回想 请参看 二 以后的笔记 20110926 注意 此文由于结构过于混乱且内容过时 将会被删除 用新的学习日记取代 如果我有时间的话 注 我只是为了学习简单的Android编程和模拟 所以没有考虑SD
  • 图示CORDIC算法

    目录 简介 原理 硬件实现 简介 CORDIC Coordinate Rotation Digital Computer 坐标旋转数字计算方法 应用 计算三角函数 cos sin tan 或者计算旋转角 原理 问题 在下图中 C点的坐标是
  • 阿里云教程安装WordPress没有 安装新插件 及 主题 的按钮

    表象 在插件页面和主题页面没有Add New的按钮 经过一番百度后 主要分为两派 文件权限问题 your wordpress site folder如果按照阿里云教程 该地址为 var www html wp blog 解决方案 chown
  • React 项目:计算器

    本教程专注于 React 部分 故对 css 及 js 不做过多解释 项目地址 yuzheng14 calculator github com 分析原型 应用中一共包含 4 个组件 APP 整个应用的整体 Display 展示输入数据及计算
  • 外网SSH远程连接linux服务器「cpolar内网穿透」

    文章目录 1 Linux CentOS安装cpolar 2 创建TCP隧道 3 随机地址公网远程连接 4 固定TCP地址 5 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下 SSH远程连接家里 公司的Linux Ce
  • SpringBoot结合Liquibase实现数据库变更管理

    从零打造项目 系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建 SpringBoot集成Mybatis项目实操 SpringBoot集成MybatisPlus项目实
  • Java利用正则表达式获取指定两个字符串之间的内容

    package com starit analyse util import java text SimpleDateFormat import java util ArrayList import java util List impor
  • CentOS 7 下使用 MySQL 5.7 + PHP 7 + Apache 部署 Nextcloud

    准备 如果你准备使用 VPS 或者云主机作为 Nextcloud 服务器的话 可以先安装一个 Xshell 注 以下代码块中 代表注释 代表 Linux 命令 姊妹篇 Ubuntu 16 04 下使用 MySQL 5 7 PHP 7 Apa
  • python对指定字符串逆序的6种方法

    对于一个给定的字符串 逆序输出 这个任务对于python来说是一种很简单的操作 毕竟强大的列表和字符串处理的一些列函数足以应付这些问题 了 今天总结了一下python中对于字符串的逆序输出的几种常用的方法 方法一 直接使用字符串切片功能逆转
  • cuda学习笔记之异步并行执行

    异步函数使得主机端与设备端并行执行 控制在设备还没有完成前就被返回给主机线程 包括 kernel启动 以Async为后缀的内存拷贝函数 device到device内存拷贝函数 存储器初始化函数 比如cudaMemset cudaMemset
  • linux离线安装llvm,Debian/Ubuntu Linux 下安装LLVM/Clang 编译器

    第一步 首先编辑 etc apt sources list 加入以下源 Debian平台 deb http llvm org apt wheezy llvm toolchain wheezy main deb src http llvm o
  • Qt将文件保存到指定目录下(另存为的功能)

    因为Qt才开始入门 对文件的操作还不是很熟练 经过一段时间查找终于找出一些适用于入门的代码 QDir d d mkpath D 123 file new QFile D 123 tmp file gt open QFile WriteOnl
  • MySQL索引实现原理分析

    目前大部分数据库系统及文件系统都采用B Tree B树 或其变种B Tree B 树 作为索引结构 B Tree是数据库系统实现索引的首选数据结构 在 MySQL 中 索引属于存储引擎级别的概念 不同存储引擎对索引的实现方式是不同的 本文主