目录 一 初识索引 二 索引的原理 三 索引的数据结构 四 聚集索引与辅助索引 五 MySQL索引管理 六 测试索引 七 正确使用索引 八 联合索引与覆盖索引 九 查询优化神器-explain 十 慢查询优化的基本步骤 可见索引的添加也是非常有技术含量的。 二 索引的原理 一 索引原理 索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。 四 聚集索引与辅助索引 在数据库中,B+树的高度一般都在2~4层,这也就是说查找某一个键值的行记录时最多只需要2到4次IO,这倒不错。 #2、and的工作原理 条件: a = 10 and b = 'xxx' and c > 3 and d =4 索引: 制作联合索引(d,a,b,c) #3、or的工作原理 条件: a = 10 or b = 'xxx' or c > 3 or d =4 索引: 制作联合索引(d,a,b,c)
文章目录 1、索引的本质 2、索引的分类 2.1、Hash 索引 2.2、二叉树 2.4、B树(二三树) 2.5、B+树 3、主键目录 4、索引页 5、索引页的分层 6、非主键索引 7.回表 1、索引的本质 索引的本质是一种排好序的数据结构。 2、索引的分类 在数据库中,索引是分很多种类的(千万不要狭隘的认为索引只有 B+ 树,那是因为我们平时使用的基本都是 MySQL)。而不同的种类很显然是为了应付不同的场合,那索引到底有那些种类呢? 2.1、Hash 索引 Hash 索引是比较常见的一种索引,他的单条记录查询的效率很高,时间复杂度为1。 但是,Hash索引并不是最常用的数据库索引类型,尤其是我们常用的Mysql Innodb引擎就是不支持hash索引的。主要有以下原因: Hash索引适合精确查找,但是范围查找不适合
前缀索引和索引选择性 ? 索引的选择性:不重复的索引值(也称为基数)和数据表的记录总数(#T)的比值,范围从1/T到1之间。 每个前缀都比原来的城市出现的次数更多,因此唯一前缀比唯一城市要少 4.增加前缀长度 直到这个前缀的选择性接近完整列的选择性。 两个前缀: ? 三个前缀: ? 四个前缀: ? city,2))/count(*) as sel2, count(distinct left(city,3))/count(*) as sel3, count(distinct left(city,4) )/count(*) as sel4, count(distinct left(city,5))/count(*) as sel5 from city_demo ? 应用场景 存储网站会话时,需要在一个很长的十六进制字符串上创建索引。此时如果采用长度为8的前缀索引通常能显著地提升性能,且对上层应用完全透明。 后缀索引 字符串反转后做前缀索引
MySQL 索引原理 现在互联网应用中对数据库的使用多数都是读较多,比例可以达到 10:1。 并且数据库在做查询时 IO 消耗较大, 所以如果能把一次查询的 IO 次数控制在常量级那对数据库的性能提升将是非常明显的,因此基于 B+ Tree 的索引结构出现了。 通过P3 指针发生第二次 IO 将磁盘块4加载到内存。再通过二分查找发现大于87,通过 P3 指针发生了第三次 IO 将磁盘块11 加载到内存。最后再通过一次二分查找找到了数据项99。 这也就是为什么索引字段要尽可能小的原因。 索引使用的一些原则。
通常大家都会根据查询的WHERE条件来创建合适的索引,不过这只是索引优化的一个方面。设计优秀的索引应该考虑到整个查询,而不单单是WHERE条件部分。 如果一个索引覆盖所有需要查询的字段的值,我们就称之为“覆盖索引”。 覆盖索引是非常有用的工具,能够极大地提高性能: 索引条目通常远小于数据行大小,所以如果只需要读取索引,那MySQL就会极大地减少数据访问量。 在所有这些场景中,在索引中满足查询的成本一般比查询行要小得多。 不是所有类型的索引都可以成为覆盖索引。 覆盖索引必须要存储索引列的值,而哈希索引、空间索引和全文索引都不存储索引列的值,所以MySQL只能使用B+Tree索引所覆盖索引。
MySQL索引原理 MySQL 的索引 概述 索引是数据库中一个排序的数据结构,用来协助快速查询和更新数据库表中的数据;数据是以文件的形式存放在磁盘上的,每一行数据都有它的磁盘地址;当没有索引时,比如从 Binary Search Trees**)是指左右子树的深度差绝对值不能超过 **1**;比如左子树的深度是 **2**,右子树的深度只能是 **1 | 3**;在这时按照顺序插入 **1、2、3、4、 **B** 树的分裂与合并演示:例如当 Max.Degree = 3 时,插入 **1、2、3** 后,在插入 **3** 时应该在第一个磁盘块,但是如果一个节点有三个关键字时,意味着有 **4** 个指针 ;子节点会变成 **4** 路,所以这时需要进行分裂,把中间的数字 **2** 提为父节点,把 **1、3** 变为 **2** 的子节点。 在删除时会有相反的合并操作,然后再继续看 **4、5** 的分裂与合并操作。
哈希索引将所有的哈希码存储在索引中,同时保存指向每个数据行的指针。 ? 如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中去。 索引只存储哈希码及行指针,所以索引的数据结构非常的紧凑,这也让哈希索引查找速度非常快,但是哈希索引也有他的限制。 哈希索引限制 哈希索引只保存哈希码和指针,而不存储字段值,所以不能使用索引中的值来避免读取行。 不过访问内存中的行速度非常快(因为是MEMORY引擎),所以对性能影响并不大 哈希索引数据并不是按照索引值顺序存储的,所以无法用于排序 哈希索引不支持部分索引列查找,因为哈希索引始终是使用索引列的全部内容来计算哈希码 全文索引 全文索引是一种特殊类型的索引,它查找的是文本中的关键字,而不是直接比较索引中值。全文索引和其他类索引的匹配方式完全不一样。
聚簇索引不是一种单独的数据类型,而是一种数据存储方式。 InnoDB的聚簇索引实际上在同一结构中保存了B+Tree索引和数据,当表有聚簇索引时,它的数据行实际上存放在索引的叶子节点中。 因为无法同时把数据行放在两个不同的地方,所以一个表只能有一个聚簇索引(覆盖索引可模拟多个聚簇索引的情况,后面会介绍) 因为是存储引擎负责实现索引,因此不是所有的存储引擎都支持聚簇索引。 本节课主要关注InnoDB,但是这里讨论的原理对于任何支持聚簇索引的存储引擎都是适用的。 聚簇索引中的记录是如何存放的? ? 叶子节点包含了全部数据,其他节点只包含索引列。 聚簇索引将索引和数据保存在同一个B+Tree中,因此从聚簇索引中获取数据通常比在非聚簇索引中查找要快。 使用覆盖索引扫描的查询可以直接使用页节点中的主键值。 二级索引访问需要两次索引查找,而不是一次。因为聚簇索引一张表就有一个,二级索引叶子节点保存着主键列,查询时首先根据索引找到对应的主键列,然后根据主键列到聚簇索引中查找数据。 ?
MyISAM使用前缀压缩来减少索引的大小,从而可以让更多的索引可以放入内存中,这在某些情况下能极大地提高性能。默认只压缩字符串,但通过参数设置也可以对整数做压缩。 MyISAM压缩每个索引块的方法是,完全保存索引块中的第一个值。然后将其他值和第一个值进行比较得到相同前缀的字节数和剩余的不同后缀部分,把这部分存储起来即可。 所有在块中查找某一行的操作平均都需要扫描半个索引快。 对于CPU密集型应用,因为扫描需要随机查找,压缩索引使得MyISAM在索引查找上要慢好几倍。压缩索引的倒序扫描就更慢了。 压缩索引需要在CPU内存资源与磁盘之间做平衡。压缩索引可能只需要十分之一大小的磁盘空间,如果是I/O密集型应用,对某些查询带来的好处会比成本多很多。 可以在create table语句中指定pack_keys参数来控制索引压缩的方式。
很多人对多列索引的理解都不够。一个常见的错误就是,为每个列创建独立的索引,或者按照错误的顺序创建多列索引。 这样一来最好的情况下也只能是“一星”索引,其性能比起真正最优的索引可能差几个数量级。有时如果无法设计一个“三星”索引,那么不如忽略掉where子句,集中精力优化索引列的顺序,或者创建一个全覆盖索引。 ,但实际上更多时候说明了表上的索引建得很糟糕: 到底什么时候创建多列索引? 当出现服务器对多个索引做相交操作时(通常有多个and操作),则意味着需要一个包含所有相关列的多列索引,而不是多个独立的单列索引。 在一个多列BTree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。
索引可以让查询锁定更少的行。如果你的查询从不访问那些不需要的行,那么就会锁定更少的行,从两个方面来看这对性能都有好处。 如果索引无法过滤掉无效的行,那么在InnoDB检索到数据并返回给服务器层以后,MySQL服务器才能应用where子句。这时已经无法避免锁定行了,InnoDB已经锁住了这些行,到适当的时候才释放。 换句话说,底层存储引擎的操作是“从索引的开头开始获取满足条件id<5的记录”,服务器并没有告诉InnoDB可以过滤第一行的WHERE条件。 就像这个例子显示的,即使使用了索引,InnoDB也可能锁住一些不需要的数据。如果不能使用索引查找和锁定行的话问题可能会更糟糕,MySQL会做全表扫描并锁住所有的行,而不管是不是需要。 关于InnoDB、索引和锁有一些很少有人知道的细节:InnoDB在二级索引上使用共享锁。
InnoDB中,主键索引则是聚集索引,数据的物理顺序与键值的逻辑(索引)顺序相同,其实就是说主键索引跟其他列的数据是存在一起的。 并且我们可以看到key_len,当前的长度是4,一般,key_len是等于所以列类型的字节长度,因为我们这条sql执行的时候是走了一个主键的索引,而主键是一个int类型,一个int类型是占4个字节,那么长度就为 4。 因为此时b是索引而d不是索引,所以执行的时候,会有4个字节,又因为b是is null的所以会多占用一个字节。 ? 现在我们将b设计为is not null,再次执行,此时的key_len就为4。 ? 那么当我们要查找a=3,b=1,e=b的时候,我们就可以直接定位到第一页的数据的第二条,但是我们可以看到当前这里只存储了4个字段的值,而我们要找的是全部字段的值,当然mysql不可能把所有列的值都存在叶子节点中
MySQL索引底层原理 局部性与页 在操作系统中,我们执行一个指令去磁盘取数据,那么他会从磁盘取出4KB数据,这个4KB就是一个局部单位,而这4KB数据就是你的指令中取出的数据周围的数据,因为操作系统认为你下一次的数据会从这条数据的周围中取 那么在Mysql的操作当中,也有这么一个原理。 ? 页数据原理 ? 当我们使用insert插入上面的语句的时候,其实可以看到插入的过程中,这4条数据已经按主键的顺序插入到MySQL中,那么在这个插入的过程是怎么样的,我们来研究一下InnoDB存储的过程。 如图,如果当我们要查找a=4的这一条数据,那么就从页目录中找,就可以立即找到该条数据会在第二组,然后在第二组中比对到了a=4之后,取出数据。
MySQL索引原理探索 索引的本质其实就是各种各样的数据结构,在增删改查的各种操作有不通的时间复杂度和空间复杂度 索引的类型 Hash索引: 参考java中的hash结构,因为其结构,查找单条数据的效率特别高 4、B+ 树查询速度更稳定:B+ 所有关键字数据地址都存在叶子节点上,所以每次查找的次数 都相同所以查询速度要比B树更稳定; 5、B+ 树天然具备排序功能:B+ 树所有的叶子节点数据构成了一个有序链表, 正式因为如此,所以一个表最多只能有一个聚簇索引。 聚簇索引是 MySQL 基于主键索引结构创建的 非主键索引 对于非主键索引,MySQL也会帮忙维护一张B+树。你有多少索引,就会维护多少B+树。 插入的原理就是这样子的。此时每个数据页中的记录存放的实际是索引字段和主键字段,而其他字段是不存的(为什么不存放? 对于非主键索引(一般都是联合索引),在维护 B+ 树的时候,会根据联合索引的字段依次去判断,假设联合索引为:name + address + age,那么 MySQL 在维护该索引的 B+ 树的时候,首先会根据
索引是什么? 定义: 索引是帮助MySQL高效获取数据的数据结构。 快速定位数据,并查询出来,这是索引干的事。 索引的文件存储形式与存储引擎有关, InnoDB 引擎的索引文件后缀是 .ibd ; MyISAM 引擎则是 .MYI 索引能快速定位数据,那它不是在内存中嘛?为啥保存在硬盘中呢? 这里说下数据结构的实现原理 hash 把key转换为int 数据,取模运算,将key存储到hash表中,数据都会加载到内存中,数据表小,没啥问题,数据大,就会耗费大量内存空间,MySQL中采用的是“自适应 那就需要4层或更深的树,于是通过磁盘查找数据多了几次 I/O 操作,严重影响数据存取速度,而影响服务器性能。 B+tree 索引的数据结构都有个小问题,如果索引的值是递增的,那么插入数据就会在新的叶子里插入,如果不是递增,就会将其中的页进行分列合并,旋转,因此索引的维护和更新比较麻烦。
在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。 答案是否定的,和一级索引(主键索引)没有什么区别。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。 MyISAM的索引方式索引和数据存放是分开的,非聚集”的,所以也叫做非聚集索引。 InnoDB索引实现 虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。 InnoDB的二级索引的叶子节点存储的不是行号(行指针),而是主键列。这种策略的缺点是二级索引需要两次索引查找,第一次在二级索引中查找主键,第二次在聚簇索引中通过主键查找需要的数据行。 数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次磁盘I/O就可以完全载入。
索引是什么? 定义: 索引是帮助MySQL高效获取数据的数据结构。 快速定位数据,并查询出来,这是索引干的事。 索引的文件存储形式与存储引擎有关, InnoDB 引擎的索引文件后缀是 .ibd ; MyISAM 引擎则是 .MYI 索引能快速定位数据,那它不是在内存中嘛?为啥保存在硬盘中呢? 这里说下数据结构的实现原理 hash 把key转换为int 数据,取模运算,将key存储到hash表中,数据都会加载到内存中,数据表小,没啥问题,数据大,就会耗费大量内存空间,MySQL中采用的是 那就需要4层或更深的树,于是通过磁盘查找数据多了几次 I/O 操作,严重影响数据存取速度,而影响服务器性能。 [B+tree] 索引的数据结构都有个小问题,如果索引的值是递增的,那么插入数据就会在新的叶子里插入,如果不是递增,就会将其中的页进行分列合并,旋转,因此索引的维护和更新比较麻烦。
重复索引 重复索引是指在相同的列上按照相同的的顺序创建相同类型的索引。应该避免这样创建重复索引,发现以后应该立即删除。 冗余索引 概念 冗余索引和重复索引有一些不同。如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引。 因此索引(A,B)也可以当做索引(A)来使用(这种冗余只是对B树索引来说的)。但是如果再创建索引(B,A),则不是冗余索引,索引(B)也不是,因为B不是索引(A,B)的最左前缀列。 另外,其他不同类型的索引(例如哈希索引)也不会是B树索引的冗余索引。 场景 冗余索引通常发生在为表添加新索引的时候。例如,有人可能会增加一个新的索引(A,B)而不是扩展已有的索引(A)。 大多数情况下都不需要冗余索引,应该尽量扩展已有的索引而不是创建新索引。但也有时候处于性能方面的考虑需要冗余索引,因为扩展已有的索引会导致其变得太大,从而影响其他使用该索引的查询的性能。
MySQL的査询优化器会通过两个API来了解存储引擎的索引值的分布信息,以决定如何使用索引。 MyISAM将索引统计信息存储在磁盘中, ANALYZE TABLE需要进行一次全索引扫描来计算索引基数。在整个过程中需要锁表。 直到 My SQL5.5版本,InnoDB也不在磁盘存储索引统计信息,而是通过随机的索引访问进行评估并将其存储在内存中。 这里需要特别提及的是索引列的基数(Cardinality),其显示了存储引擎估算索引列有多少个不同的取值。 InnoDB引擎通过抽样的方式来计算统计信息,首先随机地读取少量的索引页面,然后以此为样本计算索引的统计信息。
MyISAM 索引实现 MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录 的地址。下图是 MyISAM 索引的原理图: ? 辅助索引 在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只 是主索引要求 key 是唯一的,而辅助索引的 key 可以重复。 image.png 聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。 因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。 由于索引树是独立的, 通过辅助键检索无需访问主键的索引树。 为了更形象说明这两种索引的区别, 我们假想一个表如下图存储了 4 行数据。 其中Id 作为主索引, Name 作为辅助索引。