MySQL之索引

文章目录

    • 索引
      • 1. 什么是索引?
      • 2. 为什么要使用索引,索引的优缺点?
        • 1. 优点
        • 2. 缺点
      • 3. B树和B+树区别
      • 4. Hash索引优劣分析
      • 5. MyISAM和InnoDB实现BTree索引方式的区别
      • 6. 索引的分类
        • 1. 主键索引和二级(辅助)索引
        • 2. 聚簇索引和非聚簇索引
        • 3. 覆盖索引
      • 7. 最左前缀原则
      • 8. 索引的使用注意事项
        • 1. 索引的创建
        • 2. 注意点

索引

1. 什么是索引?

​ 索引是数据库存储引擎用于快速找到记录的一种数据结构。

2. 为什么要使用索引,索引的优缺点?

1. 优点

  1. 大大减少服务器需要扫描的数据量,加快数据检索的速度
  2. 帮助服务器避免排序和临时表,这是由于MySQL中最常见的BTree索引是按照顺序来存储数据的
  3. 可以将随机I/O变为顺序I/O
  4. 通过创建唯一的索引,可以保证数据库表中每一行的数据的唯一性
  5. 可以加速表和表之间的连接,在实现数据库的参照完整性方面有意义

2. 缺点

  1. 索引的创建和维护需要额外操作,增大了开销。
  2. 索引会占据额外的物理空间,如果建立聚簇索引则会消耗更大的空间

3. B树和B+树区别

注:根据《高性能MySQL》中所说,我们一般将其称作“B-Tree”,是因为MySQL在CREATE TABLE和其他一些操作的时候会使用到这个关键字,但实际上,底层的存储引擎可以使用不同的存储结构来实现,如B+树和T树等,但我们仍将其称作B树,不同的实现方式性能有差异。InnoDB引擎使用B+树存储索引

为什么是B/B+树?

​ 普通的二叉树会导致树过深,数据所在结点越深,需要的I/O次数越多,每次IO都是以页为单位,极大地影响了性能。但是,在增删改时由于会改变树的结构,带来了额外的开销,会导致性能的下降

  • B树的每个结点同时存放键key和数据data,而B+树仅仅在叶子结点中同时存放key和data,其余结点中只存放key,这种特性使得相同层数的B+树可以存放比B树多得多的数据。另外,B树索引可能在查询过程中还没有到达叶子节点就已经结束了,而B+树一定会到达叶子结点,这种特性使得B+树索引可以减少I/O次数
  • B树的叶子结点都是独立的,B+树的叶子结点有一个指针指向与他相邻的叶子结点。
  • 在B+树上有两个头指针,一个指向根结点,另一个指向key最小的叶子结点,在相邻的叶子结点之间形成链式结构。它们对应着B+树两种查找方式,一种是对于主键的范围查找,另一种是非主键作为搜索条件时从根节点开始进行表数据文件本身就是按照B+树组织的一个索引结构。

4. Hash索引优劣分析

在MySQL中,只有Memory引擎显示地支持Hash索引,而且支持非唯一地哈希索引,类似于HashMap,当产生哈希冲突时,索引会以链表地形式存储到同一个哈希桶中。

Hash索引是一张哈希表,它的键是哈希函数的返回值,它的值是一个指针,指向对应的行。它最大的优势就在于检索数据的速度是相当快的。

Hash索引的局限性是很明显的,包括但是不限于:

  1. 当Hash冲突大量存在时,维护索引和表的代价变得高昂,当你需要查询或者删除一行时,你需要遍历这个哈希值对应的所有行来找到你的目标
  2. Hash索引只保存了指向行的指针而不直接存储字段的值,但是由于使用Hash索引的Memory引擎使用内存来存储数据, 读取内存中的时间相对于整个查询来说是不明显的。
  3. Hash索引不按照索引值顺序来存储索引,所以不支持排序或范围查询
  4. Hash索引只有精确匹配索引所有列的查询时才有效,它不支持部分索引列匹配查找,比如,当你在“firstname”和“secondname”两列上建立哈希索引时,就无法单独使用“firstname”来使用Hash索引来进行查询。
  5. Hash索引只支持等值比较查询,包括=、in()、<=>等。

在InnoDB引擎中,提供了一种特殊的功能叫做“自适应Hash索引”,它会对使用频繁的索引值在B树索引之上创建一个Hash索引。

5. MyISAM和InnoDB实现BTree索引方式的区别

1. MyISAM

  • 在MyISAM中,B+树叶子结点的data域中存放的是数据记录的地址,也就是索引和数据是分离的。在索引检索的时候,首先按照B+树搜索算法搜索索引,如果指定的key存在,则取出data域中的值,然后以data域的地址读取相应的数据记录,这也称作是“非聚簇索引”。

  • MyISAM使用了前缀压缩技术,使得索引更小。

2. InnoDB

  • 在InnoDB中,表数据文件本身就是按照B+树组织的一个索引结构,B+树叶子结点的data域中存储了完整的数据记录,其数据文件本身就是索引文件,数据和索引是一体的。InnoDB表数据文件本身就是主索引,这种索引被称作是“聚簇索引”,而其余索引都作为辅助索引辅助索引data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。再根据主索引搜索时,直接找到key所在的结点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再在主索引中查找,也就是说,在使用辅助索引查询时,会进行两次查询,这种操作叫做“回表”。

  • InnoDB根据按照原数据格式进行存储。

①:上述说到的一些索引名称见**“索引的分类”**。

6. 索引的分类

1. 主键索引和二级(辅助)索引

  1. 主键索引
    1. 数据表的主键列使用的就是主键索引,他是一种聚簇索引
    2. 正如上面提到的,InnoDB通过B+树结构对主键创建索引,然后叶子结点中存储记录,如果没有主键,那么会选择唯一键,如果没有唯一键,会生成一个6位的row_id来作为主键
  2. 二级索引
    1. 如果创建索引的是除主键外的其他字段,《高性能MySQL》中称之为“二级索引”,是一种非聚簇索引,那么在叶子结点中存储的是该记录的主键
    2. 以下几种索引属于二级索引:
      1. 唯一索引:一张表允许有多个唯一索引,区分于被选为主键索引的唯一键,创建唯一索引的目的是为了该属性列的数据唯一性,而不是为了查询效率。
      2. 普通索引:允许有多个,允许重复和空,提高查询效率。
      3. 前缀索引:适用于字符串类型数据,对文本前几个字符创建索引
      4. 全文索引:全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6之前只有MYISAM引擎支持全文索引,5.6之后InnoDB也支持了全文索引。

2. 聚簇索引和非聚簇索引

  1. 聚簇索引
    1. 聚簇索引是索引结构和数据存储在一起的索引。
    2. 优点:查询速度相当快
    3. 缺点:严重依赖数据的有序性,增删改代价高效率低
  2. 非聚簇索引
    1. 非聚簇索引是索引结构和数据分离的索引类型。它的叶子结点存储的是主键和索引列
    2. 优点:更新代价小
    3. 缺点:依赖数据有序性,可能会导致“回表”操作。这里说可能是因为涉及到了覆盖索引
    4. 非聚簇索引未必是单列的,这又涉及到了索引的“最左匹配原则”。

3. 覆盖索引

  • 如果一个索引包含/覆盖所有需要查询的字段的值,就将它称为覆盖索引。
  • 在非聚簇索引查询时,例如InnoDB引擎使用非主键的关键字进行检索时,叶子结点的data域中存储的是主键和索引列,它需要根据这一次查询到的主键在主键索引中进行第二次查询(回表)才能查询到想要的数据。覆盖索引存在的意义就是我们想要查询的列在第一次查询时的叶子节点中都存在,这样就可以避免回表。此外,在InnoDB中,自适应Hash索引也可以减少这样的重复工作。

7. 最左前缀原则

  1. 单列索引:由一列属性构成的索引

  2. 联合索引:由多列属性组成的索引

  3. 最左前缀原则

    假设创建的联合索引为

    ALERT TABLE tablename ADD INDEX indexname (A,B,C);

    那么当查询的条件是A A AND B A AND B AND C时,索引才会生效,索引只能用于查找key是否存在(相等),遇到范围查询>、<、between、like左匹配)等就不能进一步匹配了,后续退化为线性查找。

    另外如:

    SELECT * FROM tablename WHERE A=XX AND B=XX AND C= XX; - 可以命中索引
    SELECT * FROM tablename WHERE B=XX AND C= XX; - 不能命中3
    SELECT * FROM tablename WHERE B=XX AND A=XX AND C= XX; - 可以命中索引
    

    上述第三种情况能够命中索引的原因是MySQL优化引擎回自动将其匹配成与联合索引一致的索引。

    由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDER BY子句也遵循此规则。

8. 索引的使用注意事项

1. 索引的创建

  1. 添加PRIMARY KEY(主键索引)
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) ;
  1. 添加UNIQUE(唯一索引)
ALTER TABLE `table_name` ADD UNIQUE ( `column` ) ;
  1. 添加INDEX(普通索引)
ALTER TABLE `table_name` ADD INDEX index_name ( `column` );
  1. 添加FULLTEXT(全文索引)
ALTER TABLE `table_name` ADD FULLTEXT ( `column`) ;
  1. 添加多列索引
ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` );

2. 注意点

  1. 最左前缀原则

  2. 选择合适的字段

    • 尽量不为NULL
    • 被频繁查询
    • 被作为条件查询在WHERE子句中出现
    • 被频繁用于连接的字段
  3. 不适合创建索引的字段

    • 被频繁更新的字段:维护索引成本高昂
    • 不经常查询的字段
  4. 尽可能考虑联合索引而不是单列索引

    因为索引是需要占用磁盘空间的,可以简单理解为每个索引都对应着一颗B+树。如果一个表的字段过多,索引过多,那么当这个表的数据达到一个体量后,索引占用的空间也是很多的,且修改索引时,耗费的时间也是较多的。如果是联合索引,多个字段在一个索引上,那么将会节约很大磁盘空间,且修改数据的操作效率也会提升。

  5. 注意避免冗余索引

    冗余索引指的是索引的功能相同,能够命中 就肯定能命中 ,那么 就是冗余索引如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的 在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。

  6. 考虑在字符串类型的字段上使用前缀索引代替普通索引:占用空间更小

你可能感兴趣的:(数据库,学习笔记)