MySQL索引原理详解

目录
  • 索引是什么
  • 索引数据结构
    • 树形索引
      • 树的动画
      • 为什么不是简单的二叉树?
      • 为什么不是红黑树?
      • 为什么最终选择B+树 而不是B树
      • 水平方向可以存放更多的索引key
      • 数据量估算
      • 叶子节点包含所有的索引字段
      • 叶子节点直接包含双向指针,范围查找效率高
  • Hash 索引
    • 更快
    • 不支持范围查询
    • hash 冲突问题
  • 表引擎
    • MyISAM 和 InnoDB 引擎
    • MyISAM 引擎
    • InnoDB
      • 表数据组织形式
      • 聚集与非聚集索引
    • ★★★ 为什么建议InnoDB 表必须有主键,并且是整型自增的?
      • 为什么是整型
      • 为什么是自增
  • 联合索引

索引是什么

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

最重要的点是有序的,我们用索引就是为了快速的查找数据,如果一堆数据是无序的,程序只能挨个遍历每个元素,对比值,才能找到某个元素,最坏的情况要比对N次, N 是这一堆数据的长度。如果数据是有序的,我们就可以使用二分查找算法,他的时间复杂度是 O(long N),效率比直接挨个查找快的多。

二分查找算法关键步骤就是找到区间的中间值,然后确定要查找的值落在左区间还是右区间,一直重复这个步骤直到找到该值。于是就可以将这种查询方法映射成一种数据结构——树。我们规定一种树,有左节点,右节点,和当前节点。并且左节点 < 当前节点 < 右节点 .

如下图所示: 

由于树具有方便快速查找的特性,我们一般都会使用树结构去存储索引,并对简单的查找二叉树做了很多优化,比如 红黑树,平衡二叉树, B 树 B+树

树的构建,删除, 查找都有一定的算法,这里不详细描述,只需知道树有一个通用的特性:树的高度越低,查找效率越高

所以索引的构建 , 本质上是控制树的高度

索引数据结构

二叉树:

  • 红黑树
  • Hash 表
  • B Tree

树形索引

表中的数据与索引结构映射关系可以理解如下图:

加入要找到 col2 = 23 的记录,如果不使用索引,我们需要对整张表扫描,从 34 -> 77 -> 5 -> 91 -> 22 -> 89 -> 23, 需要对比7次才能找到

使用索引时, 查找路径时是 34 -> 22 -> 23 只需对比3次就行。在表中数据量极大时,差别更明显

树的动画

推荐一个在线工具,它以动画的形式描述了每种树的构建与查找方法

为什么不是简单的二叉树?

我们知道MySQL索引采用的是 B+树,那么为什么不是其他的树呢?

因为在顺序插入下,树的高度会一直增加,等同于链表。无法控制树的高度,如下图: 

如果需要查找6,仍然需要查找6次

为什么不是红黑树?

红黑树(平衡二叉树): 虽然会自动平衡节点位置,但仍然高度不可控。表比较大时会导致树的高度很高。增加查找次数

为什么最终选择B+树 而不是B树

要解决这个疑问,我们需要知道这两种树的构造,如下图:

B Tree:

B + Tree:

水平方向可以存放更多的索引key

B+树将数据全部放到叶子节点,留下更多的空间放 key, key 越多,宽度越宽,同样的数据量,宽度越大,高度越小。查找次数就越小。

为什么需要 扩展树的宽度而不是树的深度呢?

如果按照上面的说法,我们拓宽了树的宽度,减少了树的高度,但是比较次数并没有发生改变,只不过是减少了纵向的比较,增加了横向的比较

这个疑问的前提是所有的数据都在内存中,直接在内存中进行比较大小。 但是事实并非如此,不可能把表中的所有数据都加到内存中,必须先从磁盘中加在一部分数据到内存,然后在内存中比较大小,内存中运算的速度远远大于从磁盘加载数据的速度。磁盘加载数据是机械运动,需要电机带动磁针转圈扫描磁道。内存运算则是电子运动,不可同日而语。

数据从磁盘加载到内存中,是有最小单位的,这个单位是 页, 不是 字节或者 位, 页是固定字节数据,由操作系统决定,这样可以减少加载磁盘的次数。

由于B Tree 的每一层都已经是有序的,我们把树中水平方向的数据放在磁盘相邻的地方,每次从磁盘加载一页数据时,便可以得到部分或全部的水平方向的结点,不用再次排序。

在水平方向在内存中使用二分查找的效率远远大于从磁盘中加载一页数据, 所以我们希望树越宽越好,这样一次性加载的数据就越多,而不是越高越好

对于B+ 树,我们假设要查找50这个数据,先从根节点即(15 56 77) 这些数据中找到50所处的范围,因为 (15 56 77) 已经是有序的,可以根据二分查找算法找到 50 处于 15--56之间, 然后加载 15 所指向的下一页数据 (15 20 49),再次根据二分查找算法,找到50处于 49之后,再从磁盘加载49所指向的数据页,找到50

数据量估算

MySQL 自己也有一个逻辑 页,一般是操作系统中 页 的整数倍,这个逻辑页的数据可以通过配置修改,但是不建议,MySQL 是经过大量的测试,为我们定义了一个合理的默认值 16Kb

可以通过下面语句查询:

show global status like 'Innodb_page_size'

假设上图中表示的是主键索引,类型是 bigint, 占 8 个字节。指向下一页的指针占 6 个字节, 那么这一页可以存放 16 * 1024 / (8 + 6) = 1170 个key, 同理第二页即 (15 20 49 ....) 也可以放 1170 个key , 对于第三页,也就是叶子节点,包含了主键和对应整行的数据。就按照一行数据放1KB 吧(已经比较大了) 能放 16 行,那么只有一页根节点的话, 这个索引索引树能放 1170 * 1170 * 16 =21,902,400 行数据。 这棵树的高度只有3,就已经能支持上千万的数据量了。也就是只需加载3次磁盘就可以查找到数据了。并且MySQL 存放根节点的页还有优化,可能会把这个页常驻内存。

叶子节点包含所有的索引字段

如上图所示,在主键索引中,叶子节点包含了表中的所有字段,对于一些全表扫描的查询来说,直接扫描叶子节点便可以得到数据,不用再从索引树上挨个查找

叶子节点直接包含双向指针,范围查找效率高

对于一些范围查询比如 id > 20 and id < 50, 在索引树上定位到 20 之后直接使用右向指针定位到下一个比20大的数据,依次往下,直到 50,便可以检出该区间的数据,如果没有这个指针,(B Tree)则需要再次回到索引树中去查找 , 极大的提高了范围查找的性能

Hash 索引

hash 索引原理如下: 

更快

大多情况下 Hash 索引比B+ Tree 索引更快,Hash 计算的效率非常高,且仅需一次查找就可以定位到数据(无hash冲突的情况)

不支持范围查询

图中有些歧义,Hash 后的值是没有顺序的,也不是整数,所以无法进行高效的范围查询查询

hash 冲突问题

如果在某列上有很多相同的行,比如 name 字段,叫 张三的人非常多。会产生很多次hash冲突,只能退化成列表搜索了

表引擎

我们常说的 MyISAM 引擎 或者 InnoDB 引擎是基于表的,是表的一个属性, 可不是基于数据库的, 同一个数据库中可以有不同引擎的表

MyISAM 和 InnoDB 引擎

不同引擎的表在磁盘中产生的文件也不一样,数据库文件位置默认在安装目录/data 下

MyISAM 引擎

  • frm: 表结构相关, frame(框架) 缩写`
  • MYD: MyISAM Data 表数据
  • MYI: MyISAM Index 表索引

索引结构中的叶子节点的 data 存放的是 数据行的位置,及这一行在 MYD 文件的位置, 而不是直接放的真实数据

InnoDB

  • frm 表结构信息
  • ibd 表数据加索引

表数据组织形式

表结构本身就是按照 B+ Tree 结构存储, 叶子节点放的是出索引列其他列的数据

聚集与非聚集索引

聚集索引 (InnoDB 主键索引)

叶子节点直接包含整行数据

非聚集索引 (MyISAM 索引, InnoDB 非主键索引)

叶子节点不包含整行数据,包含的是对应行所在的位置,或者主键Id

单从索引结构的来看,聚集索引的查找速度高于非聚集索引

InnoDB 只有一个聚集索引,默认是主键索引, 非主键索引的叶子节点存放的是主键的值,如下图:

这样做的目的有两个:

  • 节约空间,避免将整行的数据存放多份
  • 保证数据的一致性,否则每增加一行,对应的每个索引都要维护一份行数据。必须要等到每个索引都更新完,数据才能插入成功

★★★ 为什么建议InnoDB 表必须有主键,并且是整型自增的?

InnoDB 整个表的数据就是用B+ 树组织的,如果存在主键,就用主键为索引,叶子节点存储行数据

如果没有主键,InnoDB 就会找到一个每行数据都不相同的列作为索引来组织整个表的数据

如果没有找到这种列,就会建一个隐藏的列,自动维护值,用这个隐藏的列来组织数据,所以我们要主动做这种工作减少数据库的负担

为什么是整型

因为在查找数据的过程中,需要多次比较大小,整型的比较运算速度大于字符串, 并且占用空间小

为什么是自增

这一点涉及到B+ 树的构建,我们知道索引一个最重要的特性就是排好序 的。如果我们不是顺序插入的,那么树就要自己额外做排序,调整树结构,浪费了性能

  • 避免叶子节点的分裂
  • 避免B+ 树做平衡调整

联合索引

联合索引和单索引差不多,只不过是先按第一个字段排序,再按第二个字段排序,然后再按第三个字段排序。

这种排序规则表明了只有在第一个字段相等的情况下,第二字段才是有序的。第二字段相等的情况下,第三个字段才是有序的。

所以 name = 'Bill' and age = 20 and position = 'dev' 可以用到全部索引, 因为 name 确定了,age 是有序的,age 可以走索引, age 确定后 position 可以走索引。这个联合索引可以全部用到

如果是 name = 'Bill and age > 30 and position = 'dev'' , 首先name 可以走索引,name 确定后 age 是有序的,age 也可以走索引,但是 age > 30 导致 age 查出来的数据有多个(31 32), 31 和 32 下的 position (dev admin ) 不是有序的,便无法利用二分算法进行查找。所以无法利用 position 这个索引,这也就是左前缀法则的原理和联合索引失效的原理

到此这篇关于MySQL索引原理详解的文章就介绍到这了,更多相关MySQL索引内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL索引失效原理

    目录 1.索引失效原因 2.再来看看哪些情况会破坏索引的有序性. - 对索引字段做函数操作 - 隐式类型转换 - 隐式字符编码转换 3.总结 1.索引失效原因 首先看看哪些情况下,将会导致查找不能利用索引的有序性. 假设一个表test中有a,b,c,d四个字段,c是主键. 在a,b字段上建立联合索引(a,b):CREATE index idx_a_b on test(a,b); B+树联合索引.JPG 可以得到的规律是:优先按a字段从小到大排序,a字段相等的按b字段从小到大排序: 分析以下情况,

  • mysql索引原理与用法实例分析

    本文实例讲述了mysql索引原理与用法.分享给大家供大家参考,具体如下: 本文内容: 什么是索引 创建索引 普通索引 唯一索引 全文索引 单列索引 多列索引 查看索引 删除索引 首发日期:2018-04-14 什么是索引: 索引可以帮助快速查找数据 而基本上索引都要求唯一(有些不是),所以某种程度上也约束了数据的唯一性. 索引创建在数据表对象上,由一个或多个字段组成,这若干个字段组成"键"存储到数据结构中(B树或者哈希表).[可以根据数据结构分类成B树索引(innodb\myisam引

  • MySQL的索引原理以及查询优化详解

    目录 一.介绍 1.什么是索引? 2.为什么要有索引呢? 二.索引的原理 一 索引原理 二 磁盘IO与预读 三.索引的数据结构 四.Mysql索引管理 一.功能 二.MySQL的索引分类 三. 索引的两大类型hash与btree 四.创建/删除索引的语法 五.测试索引 1.准备 2 .在没有索引的前提下测试查询速度 3. 加上索引 六.正确使用索引 一.覆盖索引 二.联合索引 三.索引合并 七.慢查询优化的基本步骤 总结 一.介绍 1.什么是索引? 一般的应用系统,读写比例在10:1左右,而且插

  • MySQL 全文索引的原理与缺陷

    MySQL全文索引一种特殊的索引,它会把某个数据表的某个数据列出现过的所有单词生成一份清单. alter table tablename add fulltext(column1,column2) 说明: 只能在MyISAM数据表中创建 全文索引是以空格或标点隔开才能搜到的,搜中文是搜不到(有专门的应用支持中文分词可以搜中文,但都不理想) 少于3个字符的单词不会被包含在全文索引里,可以通过修改my.cnf修改选项 ft_min_word_len=3 重新启动MySQL服务器,用repair ta

  • MySQL数据库优化之索引实现原理与用法分析

    本文实例讲述了MySQL数据库优化之索引实现原理与用法.分享给大家供大家参考,具体如下: 索引 什么是索引 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的记录数量越多,这个操作的代价就越高.如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置.如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍.

  • MySQL索引机制的详细解析及原理

    目录 一.索引的类型与常见的操作 二.常见的索引详解与创建 三.索引的原理 1.通过实验介绍B+tree 2.延伸 四.聚簇索引和非聚簇索引 1.使用聚簇索引的优势 2.什么情况下无法使用索引 总结 一.索引的类型与常见的操作 前缀索引 MySQL 前缀索引能有效减小索引文件的大小,提高索引的速度.但是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用作覆盖索引(Covering Index). 复合索引 集一个索引包含多个列(最左前

  • MySql 缓存查询原理与缓存监控和索引监控介绍

    查询缓存 1.查询缓存操作原理 mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节比较,仅完全一致才被认为相同.如下,这两条语句被视为不同的查询 SELECT * FROM tb1_name Select * from tb1_name 1)不同数据库.不同协议版本,或字符集不同的查询被视为不同的查询并单独缓存. 2)以下两种类型的查询不被缓存 a.预处理语句 b.嵌套查询的子查询 3)从查询缓存抓取查询结果前,mysql检查用户对查询涉及的所有数据库和表是否有查询权限

  • MySQL索引原理详解

    目录 索引是什么 索引数据结构 树形索引 树的动画 为什么不是简单的二叉树? 为什么不是红黑树? 为什么最终选择B+树 而不是B树 水平方向可以存放更多的索引key 数据量估算 叶子节点包含所有的索引字段 叶子节点直接包含双向指针,范围查找效率高 Hash 索引 更快 不支持范围查询 hash 冲突问题 表引擎 MyISAM 和 InnoDB 引擎 MyISAM 引擎 InnoDB 表数据组织形式 聚集与非聚集索引 ★★★ 为什么建议InnoDB 表必须有主键,并且是整型自增的? 为什么是整型

  • MySQL prepare原理详解

    Prepare的好处  Prepare SQL产生的原因.首先从mysql服务器执行sql的过程开始讲起,SQL执行过程包括以下阶段 词法分析->语法分析->语义分析->执行计划优化->执行.词法分析->语法分析这两个阶段我们称之为硬解析.词法分析识别sql中每个词,语法分析解析SQL语句是否符合sql语法,并得到一棵语法树(Lex).对于只是参数不同,其他均相同的sql,它们执行时间不同但硬解析的时间是相同的.而同一SQL随着查询数据的变化,多次查询执行时间可能不同,但硬解

  • Mysql使用索引的正确方法及索引原理详解

    一 .介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重.说起加速查询,就不得不提到索引了. 什么是索引? 索引在MySQL中也叫做"键",是存储引擎用于快速找到记录的一种数据结构.索引对于良好的性能 非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要. 索引优化应该是对查询性能优化最有效的手段了.索引能

  • SQL Server2014 哈希索引原理详解

    当一个key-value键值对传递给一个哈希函数的时候,经过哈希函数的计算之后,根据结果会把key-value键值对放在合适的hash buckets(哈希存储桶)里 举个栗子 我们假设对10取模( % 10 )就是哈希函数.如果key-value键值对的key是1525 ,传递到哈希函数,那么1525 会存放在第五个bucket里 因为5 as 1525 % 10 = 5. 同样,537 会存放在第七个bucket ,2982 会存放在第二个bucket ,依次类推 同样,在hash inde

  • MySQL备份原理详解

    本文为大家介绍了MySQL备份原理,欢迎大家阅读. 备份是数据安全的最后一道防线,对于任何数据丢失的场景,备份虽然不一定能恢复百分之百的数据(取决于备份周期),但至少能将损失降到最低.衡量备份恢复有两个重要的指标:恢复点目标(RPO)和恢复时间目标(RTO),前者重点关注能恢复到什么程度,而后者则重点关注恢复需要多长时间.这篇文章主要讨论MySQL的备份方案,重点介绍几种备份方式的原理,包括文件系统快照(LVM),逻辑备份工具Mysqldump,Mydumper,以及物理备份工具Xtraback

  • MySQL索引操作命令详解

    创建索引: MySql创建索引的语法如下: CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type] ON table_name (index_col_name,...) 其中对应的语法变量信息如下: [UNIQUE|FULLTEXT|SPATIAL]:中括号中的三个关键字表示创建的索引类型,他们分别表示唯一索引.全文索引.空间索引三种不同的索引类型.如果我们不指定任何关键字,则默认为普通索引. index_name

  • mysql中的mvcc 原理详解

    目录 简介 前言 一.mysql 数据写入磁盘流程 二.redo log 1.redolog 的整体流程 2.为什么需要 redo log 三.undo log 1.undo log 特点 2.undo log 类型 3.undo log 生成过程 4.undo log 回滚过程 5.undo log的删除 四.mvcc 1.什么是MVCC 2.MVCC组成 3.快照读与当前读 快照读 当前读 五.mvcc操作演示 1.READ COMMITTED 隔离级别 2.REPEATABLE READ 

  • 详解MySQL索引原理以及优化

    前言 本文是美团一位大佬写的,还不错拿出来和大家分享下,代码中嵌套在html中sql语句是java框架的写法,理解其sql要执行的语句即可. 背景 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓"好马配好鞍",如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位描述上看到诸如"精通MySQL"."SQL语句优化"."了解数据库原理"等要求.我

  • Mysql执行原理之索引合并详解

    Mysql执行原理之索引合并详解 我们前边说过MySQL在一般情况下执行一个查询时最多只会用到单个二级索引,但存在有特殊情况,在这些特殊情况下也可能在一个查询中使用到多个二级索引,MySQL中这种使用到多个索引来完成一次查询的执行方法称之为:索引合并/index merge,在前面的成本计算中我们说到过这个概念:“我们需要分别分析单独使用这些索引执行查询的成本,最后还要分析是否可能使用到索引合并”.其实optimizer trace输出的文本中就有这个片段: 具体的索引合并算法有下边三种. In

  • Mysql数据库group by原理详解

    目录 引言 1. 使用group by的简单例子 2. group by 原理分析 2.1 explain 分析 2.2 group by 的简单执行流程 3. where 和 having的区别 3.1 group by + where 的执行流程 3.2 group by + having 的执行 3.3 同时有where.group by .having的执行顺序 3.4 where + having 区别总结 4. 使用 group by 注意的问题 4.1 group by一定要配合聚

随机推荐