数据库索引详解

这里写目录标题

数据库索引介绍

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构,主要用于加速查询。

索引是在基于数据库表创建的,它包含一个表中某些列的值以及记录对应的地址,并且把这些值存储在一个数据结构中。最常见的就是使用哈希表、B+树作为索引。

索引的优点

  1. 通过创建唯一性索引,可以保证数据库表中的每一行数据的唯一性。
  2. 可以加快数据的检索速度。
  3. 可以加速表与表之间的连接。
  4. 在使用分组和排序进行检索的时候,可以减少查询中分组和排序的时间。

索引的缺点

  1. 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  2. 索引需要占用物理空间,数据量越大,占用空间越大。
  3. 会降低表的增删改的效率,因为每次增删改索引,都需要进行动态维护。

什么时候使用索引

  1. 主键自动建立唯一索引。
  2. 频繁作为查询条件的字段应该创建索引。
  3. 查询中排序的字段创建索引将大大提高排序的速度(索引就是排序加快速查找。
  4. 查询中统计或者分组的字段。

什么时候不使用索引

①频繁更新的字段不适合创建索引,因为每次更新不单单是更新记录,还会更新索引,保存索引文件
②where条件里用不到的字段,不创建索引;
③表记录太少,不需要创建索引;
④经常增删改的表;
⑤数据重复且分布平均的字段,因此为经常查询的和经常排序的字段建立索引。注意某些数据包含大量重复数据,因此他建立索引就没有太大的效果,例如性别字段,只有男女,不适合建立索引。

Mysql索引的结构

Mysql索引主要有三种结构:B+Tree索引、FULLTEXT索引和Hash索引

Innodb存储引擎(默认是 B+Tree索引)

B+Tree是mysql使用最频繁的一个索引数据结构,是Innodb存储引擎的默认索引类型。

相对Hash索引,B+Tree在查找单条记录的速度比不上Hash索引,但是因为更适合排序等操作,所以它更受欢迎。毕竟不可能只对数据库进行单条记录的操作。B+Tree所有索引数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都有指向相邻叶子节点的指针。这样做是为了提高区间效率,例如查询key为从18到49的所有数据记录,当找到18后,只要顺着节点和指针顺序遍历就可以以此向访问到所有数据节点,极大提高了区间查询效率,大大减少磁盘I/O读取。

数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点需要一次I/O就可以完全载入。

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

MyISAM存储引擎(默认是 FULLTEXT索引)

MyISAM存储引擎默认的索引类型是FULLTEXT索引(全文索引),MySQL从3.23.23版开始支持全文索引和全文检索,全文索引仅可用于 MyISAM 表;他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATE INDEX被添加。

文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字段里存放的是由几个、甚至是多个单词构成的较大段文字,普通索引就没什么作用了。这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。

这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数据记录。

Memory存储引擎(默认是 Hash索引)

mysql中,只有Memory(Memory表只存在内存中,断电会消失,适用于临时表)存储引擎显示支持Hash索引,Hash索引是Memory表的默认索引类型,尽管Memory表也可以使用B+Tree索引。Hash索引把数据以hash形式组织起来,因此当查找某一条记录的时候,速度非常快。但是因为hash结构,每个键只对应一个值,而且是散列的方式分布。所以它并不支持范围查找和排序等功能。

MySQL索引为什么大量使用B+Tree

为什么不用Hash表

Hash索引底层是哈希表,哈希表是一种以key-value存储数据的结构,多个数据在存储关系上是完全没有任何顺序关系的,所以无法直接通过Hash索引进行范围查询,就需要全表扫描。而B+ 树是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描。

为什么不用红黑树(AVL树)

  1. MySQL中的数据一般是放在磁盘中的,磁盘读写有一个最少内容的限制,即使我们只需要这个簇上的一个字节的内容,我们也要把一整个簇上的内容读完。
  2. 在红黑树或者AVL树中,一个父节点只有 2 个子节点,并不能填满一个簇上的所有内容,那多余的空间就浪费了。而数据库设计的时候 B+ 树有多少个分支都是按照磁盘一个簇上最多能放多少节点设计的,因此B+树可以占满一整个扇区。
  3. B+ 树分支比二叉树更多,所以相同数量的内容,B+ 树的深度更浅,而深度代表磁盘的IO 次数,因此B+ 树的查询速度更快。

为什么不用B树

  1. 在数据库中基于范围的查询是非常频繁的。B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。B+树只要遍历叶子节点就可以实现整棵树的遍历,而B树这样操作的效率太低。
  2. Mysql根据磁盘IO次数衡量查询效率,磁盘IO一次读出的数据量大小是固定的,而B树的每个节点都有data域,这会增大节点大小,进一步导致磁盘IO次数的增加。B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。

B+树的查找过程

数据库索引详解

如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

索引最左前缀问题

MySQL建立多列索引(联合索引)有最左前缀的原则,即最左优先,如:

  1. 如果有一个2列的索引(col1,col2),则已经对(col1)、(col1,col2)上建立了索引。
  2. 如果有一个3列索引(col1,col2,col3),则已经对(col1)、(col1,col2)、(col1,col2,col3)上建立了索引。

最左前缀的原理

B+ 树的数据项是复合的数据结构,比如 (name,age,sex) 的时候,B+ 树是按照从左到右的顺序来建立搜索树的,比如当 (张三,20,F) 这样的数据来检索的时候,B+ 树会优先比较 name 来确定下一步的所搜方向,如果 name 相同再依次比较 age 和 sex,最后得到检索的数据。

当 (20,F) 这样的没有 name 的数据来的时候,B+ 树就不知道第一步该查哪个节点,因为建立搜索树的时候 name 就是第一个比较因子,必须要先根据 name 来搜索才能知道下一步去哪里查询。

当 (张三, F) 这样的数据来检索时,B+ 树可以用 name 来指定搜索方向,但下一个字段 age 的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是 F 的数据了, 这个是非常重要的性质,即索引的最左匹配特性。(这种情况无法用到联合索引)

索引失效的几种情况

  1. mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整(原因见第③点)。
  2. =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。
  3. 如果查询条件中含有函数或表达式,则MySQL不会为这列使用索引(虽然某些在数学意义上可以使用),因此在写查询语句时尽量避免表达式出现在查询中,而是先手工私下代数运算,转换为无表达式的查询语句。
  4. like '%abd%'不会使用索引,而like ‘aaa%’可以使用索引。
上一篇:docker安装elastic的错误


下一篇:helm3部署es kubernetes高可用集群