热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL索引和存储引擎

目录MySQL索引二叉树平衡二叉树红黑树Hash表BTreeBTreeMySQL存储引擎MyISAM存储引擎数据存储形式锁的粒度事务数据的存储特点索引实现其他**InnoDB存储引


目录

    • MySQL索引
        • 二叉树
        • 平衡二叉树
        • 红黑树
        • Hash表
        • BTree
        • B+Tree
    • MySQL存储引擎
        • MyISAM存储引擎
          • 数据存储形式
          • 锁的粒度
          • 事务
          • 数据的存储特点
          • 索引实现
          • 其他
        • **InnoDB存储引擎**
          • **数据存储形式**
          • **锁的粒度**
          • **事务**
          • **数据的存储特点**
          • **索引实现**
        • 联合索引
        • 问题总结
          • InnoDB一颗B+树可以存放多少行数据?
          • 聚簇索引和非聚簇索引的区别
          • 为什么InnoDB表必须有主键,并且推荐使用整型的自增主键?
          • MySQL为什么用自增作为索引比较好。而UUID索引效率比较低?
          • 为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)


MySQL索引

索引是帮助MySQL高效获取数据的排好序数据结构

索引数据结构,主要包含以下几类,我们来对比下


  • 二叉树
  • 平衡二叉树
  • 红黑树
  • Hash表
  • B-Tree

二叉树

**定义:**每个结点最多有两个子树,左子树比父节点小,右子树比父节点大。

缺点:会出现极端情况导致整棵树只有左子树或只有右子树。


平衡二叉树

定义:平衡二叉树又称AVL树,是一种特殊的二叉查找树,其左右子数都是平衡二叉树,且左右子树高度差的绝对值不超过1。

缺点:AVL树是高度平衡的,频繁的插入和删除,会引起频繁的rebalance,导致效率下降。


红黑树

定义:


  • 性质1. 节点是红色或黑色。
  • 性质2. 根节点是黑色。
  • 性质3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  • 性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

缺点:数据量大会导致树层数比较多,这样就会造成查找数据慢。


Hash表

定义:散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 对目标值进行hash运算得到hash值和数据磁盘指针地址保存到hash表,这样就达到快速定位数据位置。

缺点:精确查找十分快速,但范围查找就碰壁了。


BTree

定义:


  • 一个节点可以存储多个数据,这样可以避免黑红树的缺点,树的层数很变小;
  • 叶节点具有相同的深度,叶节点的指针为空;
  • 所有索引元素不重复;
  • 节点中的数据索引从左到右递增排列。

缺点:节点里面数组数据:每个数据的结构=索引数据+数据记录(即叶子节点存储键值和数据记录)。

MySQL索引是怎么支撑千万级表的快速查找?

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:


  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】

    比较关键字29在区间(17,35),找到磁盘块1的指针P2。

  2. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】

    比较关键字29在区间(26,30),找到磁盘块3的指针P2。

  3. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】

    在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。


B+Tree

定义:B+Tree是在B-Tree基础上的一种优化。节点里面数组数据:每个数据只存储键信息,这样不存数据可以腾出空间放更多的键信息,让树层数越小


  • 非叶子节点不存储data,只存储索引(冗余),可以放更多的索引
  • 叶子节点包含所有索引字段
  • 叶子节点·用指针连接,提高区间访问的性能

将上一节中的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示:

MySQL索引是怎么支撑千万级表的快速查找?

通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找分页查找,另一种是从根节点开始,进行随机查找

可能上面例子中只有22条数据记录,看不出B+Tree的优点,下面做一个推算:

InnoDB存储引擎中页的大小为16KB,一般表的主键类型为 INT(占用4个字节)或 BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值。(因为是估值,为方便计算,这里的K取值为〖10〗3)。**也就是说一个深度为3的B+Tree索引可以维护103 * 10^3 * 10^3 = 10亿 条记录**。

实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在24层。MySQL的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要13次磁盘I/O操作。

数据库中的B+Tree索引可以分为聚集索引(clustered index)和 辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。

辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。


MySQL存储引擎

数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。

现在许多数据库管理系统都支持多种不同的存储引擎。MySQL 的核心就是存储引擎。


  • InnoDB 事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。MySQL 5.5.5 之后,InnoDB 作为默认存储引擎。
  • MyISAM 是基于 ISAM 的存储引擎,并对其进行扩展,是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事务。
  • MEMORY 存储引擎将表中的数据存储到内存中,为查询和引用其他数据提供快速访问。

MySQL 提供了多个不同的存储引擎,包括处理事务安全表的引擎和处理非事务安全表的引擎。在 MySQL 中,不需要在整个服务器中使用同一种存储引擎,针对具体的要求,可以对每一个表使用不同的存储引擎。

可以利用 SHOW ENGINES 语句来显示可用的数据库引擎和默认引擎。

可以根据以下的原则来选择 MySQL 存储引擎:


  • 如果要提供提交、回滚和恢复的事务安全(ACID 兼容)能力,并要求实现并发控制,InnoDB 是一个很好的选择。
  • 如果数据表主要用来插入和查询记录,则 MyISAM 引擎提供较高的处理效率。
  • 如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存的 MEMORY 引擎中,MySQL 中使用该引擎作为临时表,存放查询的中间结果。
  • 如果只有 INSERT 和 SELECT 操作,可以选择Archive 引擎,Archive 存储引擎支持高并发的插入操作,但是本身并不是事务安全的。Archive 存储引擎非常适合存储归档数据,如记录日志信息可以使用 Archive 引擎。

使用下面的语句可以修改数据库临时的默认存储引擎 SET default_storage_engine&#61;<存储引擎名 > 注意&#xff1a;将 MySQL 数据库的临时默认存储引擎修改为 其他的存储引擎时 &#xff0c;但是当再次重启客户端时&#xff0c;默认存储引擎仍然是 InnoDB。



MyISAM存储引擎


数据存储形式

MyISAM采用的是索引与数据分离的形式&#xff0c;将数据保存在三个文件中.frm 、.MYD、.MYI。


  • .frm : 存储表结构
  • .MYD &#xff1a; 存储表数据
  • .MYI &#xff1a;存储表索引

锁的粒度

MyISAM不支持行锁&#xff0c;所以读取时对表加上共享锁&#xff0c;在写入是对表加上排他锁。由于是对整张表加锁&#xff0c;相比InnoDB&#xff0c;在并发写入时效率很低。


事务

MyISAM不支持事务


数据的存储特点

MyISAM是基于非聚簇索引进行存储的。


索引实现

MyISAM索引文件和数据文件是分离的(非聚集)


其他

MyISAM提供了大量的特性&#xff0c;包括全文索引&#xff0c;压缩&#xff0c;空间函数&#xff0c;延迟更新索引键等。


  • 进行压缩后的表是不能进行修改的&#xff0c;但是压缩表可以极大减少磁盘占用空间&#xff0c;因此也可以减少磁盘IO&#xff0c;从而提供查询性能。
  • 全文索引&#xff0c;是一种基于分词创建的索引&#xff0c;可以支持复杂的查询。
  • 延迟更新索引键&#xff0c;不会将更新的索引数据立即写入到磁盘&#xff0c;而是会写到内存中的缓冲区中&#xff0c;只有在清除缓冲区时候才会将对应的索引写入磁盘&#xff0c;这种方式大大提升了写入性能。

InnoDB存储引擎


数据存储形式

使用InnoDB时&#xff0c;会将数据表分为.frm 和 .ibd 两个文件进行存储。


  • .frm : 存储表结构
  • .ibd : 存储表数据和索引

innodb的所有数据文件&#xff08;后缀为ibd的文件&#xff09;&#xff0c;他的大小始终都是16384&#xff08;16k&#xff09;的整数倍



锁的粒度

InnoDB采用**MVCC(多版本并发控制)**来支持高并发&#xff0c;InnoDB实现了四个隔离级别&#xff0c;默认级别是REPETABLE READ&#xff0c;并通过间隙锁策略防止幻读的出现。它的锁粒度是行锁。【MVCC在稍后会进行介绍】


事务

InnoDB是典型的事务型存储引擎&#xff0c;并且通过一些机制和工具&#xff0c;支持真正的热备份。


数据的存储特点

InnoDB表是基于聚簇索引建立的&#xff0c;聚簇索引对主键的查询有很高的性能&#xff0c;不过他的二级索引&#xff08;非主键索引&#xff09;必须包含主键列&#xff0c;索引其他的索引会很大。


索引实现

InnoDB索引实现(聚簇)


  • 表数据文件本身就是按B&#43;Tree组织的一个索引结构文件
  • 聚簇索引-叶节点包含了完整的数据记录
  • 为什么InnoDB表必须有主键&#xff0c;并且推荐使用整型的自增主键&#xff1f;
  • 为什么非主键索引结构叶子节点存储的是主键值&#xff1f;(一致性和节省存储空间)

联合索引

底层数据结构&#xff1a;

比较相等时&#xff0c;先比较第一列的值&#xff0c;如果相等&#xff0c;再继续比较第二列&#xff0c;以此类推。

MySQL索引是怎么支撑千万级表的快速查找&#xff1f;

最左前缀原理&#xff1a;

使用联合索引时&#xff0c;索引列的定义顺序将会影响到最终查询时索引的使用情况。例如联合索引&#xff08;a,b,c&#xff09;&#xff0c;mysql会从最左边的列优先匹配&#xff0c;如果最左边的带头大哥没有使用到&#xff0c;在未使用覆盖索引的情况下&#xff0c;就只能全表扫描。 联合底层数据结构思考&#xff0c;mysql会优先以联合索引第一列匹配&#xff0c;此后才会匹配下一列&#xff0c;如果不指定第一列匹配的值&#xff0c;也就无法得知下一步查询哪个节点。 另外还有一种情况&#xff0c;如果遇到 >

问题总结


InnoDB一颗B&#43;树可以存放多少行数据&#xff1f;

这个问题的简单回答是&#xff1a;约2千万。为什么是这么多呢&#xff1f;因为这是可以算出来的。

这里我们先假设B&#43;树高为2&#xff0c;即存在一个根节点和若干个叶子节点&#xff0c;那么这棵B&#43;树的存放总记录数为&#xff1a;根节点指针数单个叶子节点记录行数

上文我们已经说明单个叶子节点&#xff08;页&#xff09;中的记录数&#61;16K/1K&#61;16。&#xff08;这里假设一行记录的数据大小为1k&#xff0c;实际上现在很多互联网业务数据记录大小通常就是1K左右&#xff09;。

那么现在我们需要计算出非叶子节点能存放多少指针&#xff0c;其实这也很好算&#xff0c;我们假设主键ID为bigint类型&#xff0c;长度为8字节&#xff0c;而指针大小在InnoDB源码中设置为6字节&#xff0c;这样一共14字节&#xff0c;我们一个页中能存放多少这样的单元&#xff0c;其实就代表有多少指针&#xff0c;即16384/14&#61;1170。那么可以算出一棵高度为2的B&#43;树&#xff0c;能存放1170*16&#61;18720条这样的数据记录。

根据同样的原理我们可以算出一个高度为3的B&#43;树可以存放&#xff1a;1170* 1170 *16&#61;21902400条这样的记录。所以在InnoDB中B&#43;树高度一般为1-3层&#xff0c;它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO&#xff0c;所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。


聚簇索引和非聚簇索引的区别

  • 聚簇索引&#xff1a;将数据存储与索引放到了一块&#xff0c;索引结构的叶子节点保存了行数据
  • 非聚簇索引&#xff1a;将数据与索引分开存储&#xff0c;索引结构的叶子节点指向了数据对应的位置

为什么InnoDB表必须有主键&#xff0c;并且推荐使用整型的自增主键&#xff1f;

  1. 如果设置了主键&#xff0c;那么InnoDB会选择主键作为聚集索引&#xff0c;如果没有显式定义主键&#xff0c;则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引、如果也没有这样的唯一索引&#xff0c;则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增)。
  2. 如果表使用自增主键

那么每次插入新的记录&#xff0c;记录就会顺序添加到当前索引节点的后续位置&#xff0c;主键的顺序按照数据记录的插入顺序排列&#xff0c;自动有序。当一页写满&#xff0c;就会自动开辟一个新的页


  1. 如果使用非自增主键&#xff08;如果身份证号或学号等&#xff09;

由于每次插入主键的值近似于随机&#xff0c;因此每次新纪录都要被插到现有索引页得中间某个位置&#xff0c;此时MySQL不得不为了将新记录插到合适位置而移动数据&#xff0c;甚至目标页面可能已经被回写到磁盘上而从缓存中清掉&#xff0c;此时又要从磁盘上读回来&#xff0c;这增加了很多开销&#xff0c;同时频繁的移动、分页操作造成了大量的碎片&#xff0c;得到了不够紧凑的索引结构&#xff0c;后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。


MySQL为什么用自增作为索引比较好。而UUID索引效率比较低&#xff1f;

聚簇索引的数据的物理存放顺序与索引顺序是一致的&#xff0c;即&#xff1a;只要索引是相邻的&#xff0c;那么对应的数据一定也是相邻地存放在磁盘上的。如果主键不是自增id&#xff0c;那么可以想象&#xff0c;它会干些什么&#xff0c;不断地调整数据的物理地址、分页&#xff0c;当然也有其他一些措施来减少这些操作&#xff0c;但却无法彻底避免。但&#xff0c;如果是自增的&#xff0c;那就简单了&#xff0c;它只需要一页一页地写&#xff0c;索引结构相对紧凑&#xff0c;磁盘碎片少&#xff0c;效率也高。


  • 索引存储在磁盘&#xff0c;而且树的每个节点分配的空间有大小。整型占空间比较小&#xff0c;这样可以存放多个键值。反之然后UUID占空间比较大。
  • 整型比较方便&#xff0c;UUID比较需要先转成ASCII在进行比较。

为什么非主键索引结构叶子节点存储的是主键值&#xff1f;&#xff08;一致性和节省存储空间&#xff09;

  1. 减少了出现行移动或者数据页分裂时二级索引的维护工作&#xff08;当数据需要更新的时候&#xff0c;二级索引不需要修改&#xff0c;只需要修改聚簇索引&#xff0c;一个表只能有一个聚簇索引&#xff0c;其他的都是二级索引&#xff0c;这样只需要修改聚簇索引就可以了&#xff0c;不需要重新构建二级索引&#xff09;&#xff1b;
  2. 聚簇索引也称为主键索引&#xff0c;其索引树的叶子节点中存的是整行数据&#xff0c;表中行的物理顺序与键值的逻辑&#xff08;索引&#xff09;顺序相同。一个表只能包含一个聚集索引。因为索引&#xff08;目录&#xff09;只能按照一种方法进行排序&#xff1b;
  3. 非聚簇索引&#xff08;普通索引&#xff09;的叶子节点内容是主键的值。在 InnoDB 里&#xff0c;非主键索引也被称为二级索引&#xff08;secondary index&#xff09;。

推荐阅读
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 本文深入解析了JDK 8中HashMap的源代码,重点探讨了put方法的工作机制及其内部参数的设定原理。HashMap允许键和值为null,但键为null的情况只能出现一次,因为null键在内部通过索引0进行存储。文章详细分析了capacity(容量)、size(大小)、loadFactor(加载因子)以及红黑树转换阈值的设定原则,帮助读者更好地理解HashMap的高效实现和性能优化策略。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 在使用 Cacti 进行监控时,发现已运行的转码机未产生流量,导致 Cacti 监控界面显示该转码机处于宕机状态。进一步检查 Cacti 日志,发现数据库中存在 SQL 查询失败的问题,错误代码为 145。此问题可能是由于数据库表损坏或索引失效所致,建议对相关表进行修复操作以恢复监控功能。 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 本文介绍了如何在 Spring 3.0.5 中使用 JdbcTemplate 插入数据并获取 MySQL 表中的自增主键。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • MySQL 5.7 学习指南:SQLyog 中的主键、列属性和数据类型
    本文介绍了 MySQL 5.7 中主键(Primary Key)和自增(Auto-Increment)的概念,以及如何在 SQLyog 中设置这些属性。同时,还探讨了数据类型的分类和选择,以及列属性的设置方法。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • MySQL作为一款广泛使用的关系型数据库管理系统,在实际应用中,许多用户习惯于使用root账户进行操作,但这会带来显著的安全隐患。本文将详细探讨如何通过创建专用账户和实施严格的权限管理,有效规避以root用户运行MySQL所带来的潜在安全威胁。同时,文章还将提供一系列最佳实践,帮助用户增强数据库的整体安全性。 ... [详细]
author-avatar
heishi86188
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有