Mysql数据查询优化——索引的数据结构

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: Mysql数据查询优化——索引的数据结构

正文


什么是索引


在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。


索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。


当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。——百度百科


索引的数据结构


数据结构有数组、链表、二叉树、平衡二叉树、红黑树、hash表、b-tree、b+tree等。但是常用作索引的有平衡二叉树、红黑树、hash表、b-tree、b+tree。下面分别介绍一下他们的特点。


二叉树和平衡二叉树


222.png


如上图第一个是二叉树,第二个是平衡二叉树,同样存储的是1-6的值。二叉树是一个树,其中每个节点都不能有多于两个节点。二叉树和平衡二叉树一样,都是左边的数比根节点的小,右边的数比根节点的大。第一个图展示了最差的一种二叉树。平衡二叉树是带有平衡条件的二叉树,必须保证树的深度是O(logN),而且左子树和右子树的高度最多相差1。二叉树理想的增删改查时间复杂度是O(logN),而最坏的情况是O(N),而平衡二叉树的增删改查时间复杂度最坏和理想都是O(logN)。


红黑树(R-BTree)


8074245061964fd5a3b4850740109991.png


上图是红黑树存储1-6的数据结构。从图上可以看出红黑树特点如下


每个节点是黑色或者红色。

根结点是黑色。

红黑树每个叶子节点都要是黑色的空节点,也就是说,叶子节点不存储数据。

如果一个节点是红色的,则它的子节点必须是黑色的。也就是说红黑树中两个相邻的节点不能同时为红色。

红黑树中每个节点,从该节点到达其可达叶子节点(null的节点)的所有路径,都要包含相同数目的黑色节点。

红黑树可以看成是一种特殊的平衡二叉树,所以他的增删改查的时间复杂度同平衡二叉树一样也是O(logN)。


hash


每次存入数据就会对key进行一次hash,计算出存储的位置。但是hash会出现hash碰撞,对于不同的key值可能计算出的结果是一样的。查找数据的时候先对key进行hash计算出所在位置,如果所在位置有多个,在进行key的比较。很多时候hash会比b+tree的效率高,因为key值hash后就能找到对应的位置。但是hash结构的数据不适合做范围查询。mysql是可以选择hash作为索引的。例如在查找历史订单的时候,以年份为查找条件,此时就可以考虑使用hash索引。hash的时间复杂度是O(1)。


B-tree


111.png


如上图是建立一个深度是3的B-tree存放1-6的值。如图可知B-tree的特点


叶节点具有相同的深度,叶节点的指针为空。

所有的元素不重复

所有的元素从左到右依次递增。

B-tree增删改查的时间复杂度是O(logN)。


B+tree


333.png


由图可知B+tree把所有的数据都放在叶子节点中,根节点和子节点存储的数据是叶子节点的地址。每个子节点的两端同样指向下一个子节点。同时叶子节点多了指针指向下一个节点。mysql底层索引也没有用这个b+tree,而是优化过的b+tree。


Mysql B+tree索引的数据结构


111.png


那么这样的数据结构特点是什么呢?


非叶子节点不存储data,只存储索引(冗余),可以放更多的索引。

叶子节点包含所有索引字段(查询的字段包含在联合索引内的好处)。

叶子节点用指针连接,提高区间访问的性能。

每个节点都是按照递增顺序排序,并且满足二叉树的左小右大的特点。

每个叶子节点的两端也保存相邻叶子节点的地址,就是说可以通过20,很快找到18所在的数据,这就是双向箭头的作用。


如何查找数据:


先从根节点开始查找,把根节点的数据放入到内存当中,然后采用类似二分法的方式查找。这算一次IO,但是因为在内存当中这次IO是非常快,真正耗费时间的是从根节点定位到子节点,再从子节点定位到叶子节点。例如查找56,可以直接在根节点找到,那么根节点的56所存储是叶子节点56所在的位置,就会定位到叶子节点56的位置,就可以找到数据。 例如查找20,在根节点中找不到,那么根节点15和56之间的空白处就是存储了子节点的地址,就会访问子节点继续按照这个模式查找。


我们知道树的高度影响着查找的性能,那么B+tree是如何满足mysql的呢?


索引一般以文件形式存储在磁盘上,索引检索需要磁盘I/O操作。与主存不同,磁盘I/O存在机械运动耗费,因此磁盘I/O的时间消耗是巨大的。一个磁盘由大小相同且同轴的圆形盘片组成,磁盘可以转动(各个磁盘必须同步转动)。在磁盘的一侧有磁头支架,磁头支架固定了一组磁头,每个磁头负责存取一个磁盘的内容。磁头不能转动。盘片被划分成一系列同心环,圆心是盘片中心,每个同心环叫做一个磁道,所有半径相同的磁道组成一个柱面。磁道被沿半径线划分成一个个小的段,每个段叫做一个扇区,每个扇区是磁盘的最小存储单元。当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点,磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间,然后磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。


由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:


当一个数据被用到时,其附近的数据也通常会马上被使用。程序运行期间所需要的数据通常比较集中。


由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。


预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页的大小通常为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。在mysql中根节点或者子节点称为数据页,每个数据页为16kb,通过


SHOW GLOBAL STATUS LIKE 'Innodb_page_size';


222.png

根据B+tree的结构图,假设主键key用bigint,bigint在mysql中占8(64位)个字节,空白处为子节点的磁盘地址,大约占6个字节。那么每个数据页大约能放(16384/(8+6))约等于1170个元素(一个key+一个指针),叶子节点特殊一些,叶子节点因为包含数据,就算它一条数据1kb,那么能存储16个元素(mysql存储的数据)。所以一个B+tree能存储1170*1170*16大约两千万左右的数据。也就是说千万级别的数据放在高度为3的树中,也就是说查找只需要3次IO。

为什么mysql使用B+tree而不是B-tree

B-tree根节点、子节点、和叶子节点有存储了数据。极大的占用了空间,按照上面B+tree的算法,B-tree每个数据页只能存放16个元素,那么如果存放千万级别数据,需要的高度大于3。


MySql索引


在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。


MyISAM索引实现


MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:


444.png


假设表一共有三列,假设我们以Col1为主键,则上图是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示:


333.png


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


MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。B+tree的叶子节点的只包含了部分数据,例如主键,那么这就是非聚集索引。例如除了主键索引外,其他的辅助索引,叶子节点的数据包含的是主键,然后根据这个主键进行回表,根据聚集索引获取到对应的数据。


InnoDB索引实现


虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。


222.png


上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引(聚簇索引)。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),而且建议使用整形自增的列做主键,如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。为什么使用整形主键?因为整形相对于字符串来说比较大小的效率会高,因为在B+tree中不管是叶子节点还是根节点、子节点都是排好序的,同时整形存储需要的空间比字符串需要的空间要小。

为什么要使用自增主键?在B+tree中都是需要排好序的,如果选择自增,那么插入的时候只需要往后面插入数据就好。如果不是自增,那么数据插入后索引会进行维护,自动排好序,并且有可能做平衡转化。


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


111.png


辅助索引都存储了主键,通过索引查找到主键,在通过主键回表查询数据的过程,我们称之为回表,回表无疑降低了查询效率,这也就是为什么不建议使用select * 的原因之一。


参考


https://blog.csdn.net/admin522043032/article/details/120987864

https://blog.csdn.net/lihongjing/article/details/91388823

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
85 4
|
3月前
|
SQL 缓存 关系型数据库
MySQL 慢查询是怎样优化的
本文深入解析了MySQL查询速度变慢的原因及优化策略,涵盖查询缓存、执行流程、SQL优化、执行计划分析(如EXPLAIN)、查询状态查看等内容,帮助开发者快速定位并解决慢查询问题。
127 0
|
18天前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
58 6
|
2月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
|
2月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
105 0
|
4月前
|
存储 SQL 关系型数据库
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
|
6月前
|
存储 关系型数据库 MySQL
MySQL细节优化:关闭大小写敏感功能的方法。
通过这种方法,你就可以成功关闭 MySQL 的大小写敏感功能,让你的数据库操作更加便捷。
421 19
|
7月前
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
237 9
|
6月前
|
存储 关系型数据库 索引
索引的底层数据结构
索引是在存储引擎中实现的,也就是说不同的存储引擎,会使用不同的索引 MyISAM和InnoDB存储引擎:只⽀支持B+ TREE索引, 也就是说默认使用BTREE,不能够更换 MEMORY/HEAP存储引擎:支持HASH和BTREE索引
|
3月前
|
人工智能 运维 关系型数据库
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
584 1

推荐镜像

更多