Java教程

数据库索引

本文主要是介绍数据库索引,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

    • 1. 基础概念
    • 2. 避免索引失效
    • 3. 聚簇索引与辅助索引
    • 4. 覆盖索引
    • 5. 最左前缀原则
    • 6. 冗余索引



1. 基础概念

索引概念:

  • 它是帮助mysql高效获取数据的数据结构
  • 索引以某种方式指向数据,通过索引可以快速获取数据;
  • 没有索引时,查找,只能遍历,O(N)的时间复杂度 (避免全表扫描)
  • 建立了索引,查找速度就显著提高,一般是B+树索引,且索引像目录,可提高查询效率;
  • 通过索引对数据进行排序,降低排序成本;

索引劣势:

  • 索引本身是一张表,保存了主键与索引字段,并指向实体类的记录,所以其也要存储空间,一般放到磁盘
  • 插入数据时也要更新索引,从而影响写入数据的效率

索引结构:

  • 不同的存储引擎,它的索引是不一样的
  • BTREE索引是最常见的,也是InnoDB引擎所支持的索引

hash索引缺点:

  • hash不能够进行范围查找;
  • hash键值对的形式使得其键只能用一个,导致只能主键查询,不能用其它字段建立索引查询;
  • hash冲突(不论邻接法还是开链法)都有一定线性时间的查找,不一定比B+树索引快;

对于B树和B+树的相关内容见:B树、B+树详解。

索引分类:

  • 单值索引:(单列索引)按照单列,一个表可以有多个;
  • 唯一索引:索引值必须唯一,允许有空值;
  • 复合索引:多个列一起构成索引;

索引语法:

  • 可以在创建表时创建,也可以之后创建
  • mysql中主键有默认的索引 PRIMARY
  • 索引类型默认是BTREE
  • 可以create,也可以alter

索引的设计原则:

  • 对于查询频次高,且数据量比较大的表
  • 针对 经常在where子句中出现的字段
  • 尽量使用唯一索引,区分度高,索引效率高
  • 并不是多多益善,在insert,update和delete也要维护
  • 使用短字段的索引,节省空间
  • 针对复合(联合)索引,创建一个组合索引,其所有子集(从左边连续),都有索引(最左前缀);

索引是越多越好吗:

  • 数据量小的表不需要索引,建立会增加额外的开销
  • 数据变更需要维护索引,因此需要更多的维护成本
  • 索引本身需要空间


2. 避免索引失效

  • 全值匹配,对索引中所有列都指定具体值(该情况下,索引生效,执行效率高);
  • 最左前缀法则,如果索引了多列,要遵守最左前缀法则。即查询从索引的最左前列开始(从最左前列开始,不管其相对位置),且不跳过索引中的列(若是跳过,查询时从跳过处截断);
  • ③范围查询右边的列,不能够使用索引,即范围查询右边的查询条件失效;
  • ④不要在索引列上进行运算操作,索引将失效;
  • ⑤字符串不加单引号,造成索引失效;
  • ⑥尽量使用覆盖索引(只访问索引的查询(索引列完全包含查询列)),减少select *
    explain中的Extra字段含义:
    (1)using index:使用覆盖索引的时候出现;
    (2)using where:在查找使用索引的情况下,需要回表去查询所需数据;
    (3)using index condition:查找使用了索引,但是需要回表查询数据;
    (4)using index; using where:查找使用了索引,但是需要的数据都在索引中能找到,所以不需要回表查询数据;
  • ⑦用 or分隔开的条件,如果 or 前的条件中的列有索引,而后边的列中没有索引,那么涉及的索引都不会被用到;
  • ⑧以%开头的like模糊查询,索引失效,如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。解决办法是使用覆盖索引来搭配前部模糊查询条件;
  • ⑨如果Mysql评估使用索引比全表慢,则不使用索引;
    (1)is NULL,is NOT NULL有时索引失效,原因是索引内的数据的成分;
  • ⑩in 走索引,not in 索引失效;
  • ⑾单列索引和复合索引,尽量使用复合索引(相当于创建了索引列个数的索引)而非单列索引(此时数据库会选择一个最优的索引,辨识度最高的来使用,并不会使用全部索引);


3. 聚簇索引与辅助索引

  • 聚簇索引的叶子节点包含全部的数据信息,即除了该索引字段的话也有剩余其他所有字段的数据;
  • 辅助索引中叶子节点可能只有指向行数据的指针,or 主键;
  • 在InnoDb和MyISAm中,是不一样的,可以看下面图;
  • 左边的需要两次查询,这是一个回表;
  • 对于InnoDB,其必有聚簇索引;


4. 覆盖索引

  • 只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。

  • 就是索引本身就已经包含了 所要查询的列。

  • 则此时就不用进行回表,直接返回就好

  • 哈希索引、空间索引等索引都把存储索引列的值,所以mysql只能使用B-TREE来做覆盖索引

  • image-20210716145738440

  • 这里Extra,如果using index,就是覆盖索引(见上文)

    • using where 回表查询
    • using index 覆盖索引
    • using index condition 部分条件不能索引, 所以先用能索引的先走一遍, 然后再使用不能用索引的条件
    • 如果type是ALL,则是全表查询
  • 主键是不需要加入聚集索引的,因为它本身就在索引的data中

  • 这也引出一个问题,非聚集索引不一定回表(如果是覆盖索引,或者是主键)

  • MySQL 的覆盖索引与回表 - 知乎 (zhihu.com)这个写的不错, 忘记了看这个

  • 什么时候发生覆盖索引

    • 比如where 非主键字段, select 主键, 非主键字段, 此时, 本身非主键字段就在索引树上, 其次非聚集索引叶子存储的是主键, 所以一颗索引树就覆盖了查询的结果
    • 比如where 非主键字段 命中了联合索引的左边, 那么select 联合索引中的字段, 就会发生覆盖索引
  • 什么时候需要用覆盖索引

    • 全表count查询, 建立count(字段), 该字段的索引, 可以直接通过索引得到结果, 不然要回表
    • select 多个字段, 可以考虑建立联合索引来覆盖


5. 最左前缀原则

  • 对于联合索引,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。

  • 这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。

  • 如果遇到范围查询时,就停止匹配了

  • 最左匹配的成因:mysql按照联合索引的顺序,以第一个字段排序,然后再这个基础上再按第二个字段排序,所以对于第二个字段,实际它是局部有序,整体无序的,所以不能跳过第一个字段,直接从第二个字段开始进行,所以最左匹配原则

  • 举个例子:

  • 如User表的name和city加联合索引就是(name,city)

  • select * from user where name=xx and city=xx ; //可以命中索引
    select * from user where name=xx ; // 可以命中索引
    select * from user where city=xx ; // 无法命中索引     
    


6. 冗余索引

  • 如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的
这篇关于数据库索引的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!