mysql 索引(待补充)

一、索引

1、什么是索引

  在关系数据库中,索引是一种数据结构他将数据提前按照一定的规则进行排序和组织, 能够帮助快速定位到数据记录的数据,

加快数据库表中数据的查找和访问速度。像书籍的目录、文件夹、标签 、房号.... 都可以帮助我们快速定位,都可以视为索引。

能实现快速定位数据的一种存储结构,其设计思想是以空间换时间

2、索引的种类

在MySQL中索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。常见的索引分类如下:

● 按数据结构分类:B+tree索引、Hash索引、Full-text索引。

● 按物理存储分类:聚集索引、非聚集索引。

● 按字段特性分类:主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)。

● 按字段个数分类:单列索引、联合索引(也叫复合索引、组合索引)。

3、常见索引的数据结构和区别

二叉树

红黑树

B 树

B+ 树

区别:树的高度影响获取数据的性能(每一个树节点都是一次磁盘I/O)

二叉树:

特点:每个节点最多有两个子节点, 大在右,小在左 ,数据随机性情况下树杈越明显。

如果数据是按顺序依次进入:
树的高度则会很高(就是一个链表结构), 此时元素的查找效率就等于链表查询O(n),数据检索效率将极为低下。

极端的情况下 就是一个链表结构(如下图),此时元素的查找效率就等于链表查询O(n)。

红黑树(平衡二叉树) 

虽通过自旋平衡,子节点会自动分叉为2个分支,从而减少树的高度,当数据有序插入时比二叉树数据检索性能更佳.
但是如果 数据量过大,节点个数就越多,树高度也会增高(也就是树的深度越深),增加磁盘I/O次数,影响查询效率。

B-树(多叉树)

B树 的出现可以解决树高度的问题。之所以是B树,而并不是名称中"xxx二叉树",就是它不再限制一个父节点中只能有两个子节点,而是允许 M 个子节点(M > 2)。

不仅如此,B树的一个节点可以存储多个元素,相比较于前面的那些二叉树数据结构又将整体的树高度降低了。

B 树的节点可以包含有多个字节点,所以 B树是一棵多叉树,它的每一个节点包含的最多子节点数量的称为B树的阶。如下图是一颗3阶的B树。 

 

当一颗3阶的B树查找 7这个的元素时的流程是怎么样的?
先从根节点出发 ,判断 7在4和8之间,根据P2存储指针6的节点,判断7大于6 最后指针找到叶子节点。也就找到有匹配7的键值。

可以发现一颗3阶的B树在查找叶子节点时,由于树高度只有 3,所以查找过程最多只需要3次的磁盘I/O操作。

数据量不大时可能不太真切。但当数据量大时,节点也会随着增多;此时如果还是前面的自平衡二叉树的场景下,由于二叉树只能最多2个叶子节点的约束,

也只能纵向去的去扩展子节点,树的高度会很高,意味着需要更多的操作磁盘I/O次数。而B树则可以通过横向扩展节点从而降低树的高度,所以效率自然要比二叉树效率更高。(直白说就是变矮胖了)

看到这,相信你也知道如果B树这么适合,也就没有接下来B+树的什么事了。

接着,那为什么不用B树,而用了B+树呢?

你看啊,B树其实已经满足了我们最前面所要满足的条件,减少磁盘I/O操作,同时支持按区间查找。但注意,虽然B树支持按区间查找,但并不高效。

例如上面的例子中,B树能高效的通过等值查询 15 这个值,但不方便查询出一个区间内3 ~ 10区间内所有数的结果。

因为当B树做范围查询时需要使用中序遍历,那么父节点和子节点也就需要不断的来回切换涉及了多个节点会给磁盘I/O带来很多负担。

B+tree索引

B+tree 是在B树基础上的一种优化,其更适合做存储索引结构。在 B+tree 中,非叶子节点上仅存储键值,不存储数据;而所有数据记录均存储在叶子节点上,

并且数据是按照顺序排列的。此外在 B+tree 中各个数据页之间是通过双向链表连接的。B+tree 的结构图如下:

 B树和B+树的区别,Mysql为什么要选择B+树作为默认索引的数据结构

 

 

B+tree 结构实现数据索引具有如下优点:

a. 非叶子节点上可以存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树也就会变得更矮更胖。这样一来我们查找数据进行磁盘I/O的次数就会大大减少,数据查询的效率也会更快。

b. 所有数据记录都有序存储在叶子节点上,就会使得范围查找,排序查找,分组查找以及去重查找变得异常简单。

c. 数据页之间、数据记录之间都是通过链表链接的,有了这个结构的支持就可以方便的在数据查询后进行升序或者降序操作。

Hash索引

Hash索引其实用的不多,最主要是因为最常见的存储引擎InnoDB不支持显示地创建Hash索引,只支持自适应Hash索引。

虽然可以使用sql语句在InnoDB显示声明Hash索引,但是其实是不生效的

对name字段建立Hash索引,但是通过show index from 表名就会发现实际还是B+树

show index from 表名可以查看索引类型

在存储引擎中,Memory引擎支持Hash索引

Hash索引其实有点像Java中的HashMap底层的数据结构,他也有很多的槽,存的也是键值对,键值为索引列,值为数据的这条数据的行指针,通过行指针就可以找到数据

假设现在user表用Memory存储引擎,对name字段建立Hash索引,表中插入三条数据 

Hash索引会对索引列name的值进行Hash计算,然后找到对应的槽下面,如下图所示

当遇到name字段的Hash值相同时,也就是Hash冲突,就会形成一个链表,比如有name=张三有两条数据,就会形成一个链表。

之后如果要查name=李四的数据,只需要对李四进行Hash计算,找到对应的槽,遍历链表,取出name=李四对应的行指针,然后根据行指针去查找对应的数据。

Hash索引优缺点
  • hash索引只能用于等值比较,所以查询效率非常高
  • 不支持范围查询,也不支持排序,因为索引列的分布是无序的

二、聚簇索引与非聚集索引和区别?

1、按物理存储分类:InnoDB的存储方式是聚集索引,MyISAM的存储方式是非聚集索引。

聚簇索引
聚簇索引将数据存储在索引树的叶子节点上。
聚簇索引可以减少一次查询,因为查询索引树的同时就能获取到数据。
聚簇索引的缺点是,对数据进行修改或删除操作时需要更新索引树,会增加系统的开销。
聚簇索引通常用于数据库系统中,主要用于提高查询效率。

 

非聚簇索引(又称二级索引 /  辅助索引)

非聚簇索引不将数据存储在索引树的叶子节点上,而是存储在数据页中。
非聚簇索引在查询数据时需要两次查询,一次查询索引树,获取数据页的地址,再通过数据页的地址查询数据(通常情况下来说是的,但如果索引覆盖的话实际上是不用回表的)。
非聚簇索引的优点是,对数据进行修改或删除操作时不需要更新索引树,减少了系统的开销。
非聚簇索引通常用于数据库系统中,主要用于提高数据更新和删除操作的效率。 

2、二级索引
在MySQL中,创建一张表时会默认为主键创建聚簇索引,B+树将表中所有的数据组织起来,即数据就是索引主键所以在InnoDB里,主键索引也被称为聚簇索引,索引的叶子节点存的是整行数据。而除了聚簇索引以外的所有索引都称为二级索引,二级索引的叶子节点内容是主键的值。
CREATE TABLE users(
  id INT NOT NULL,
  name VARCHAR(20) NOT NULL,
  age INT NOT NULL,
  PRIMARY KEY(id)
);
新建一个以age字段的二级索引:

ALTER TABLE users ADD INDEX index_age(age);
MySQL会分别创建主键id的聚簇索引和age的二级索引:

在MySQL中主键索引的叶子节点存的是整行数据,而二级索引叶子节点内容是主键的值.

3、回表

 

 
 
 
 
 

 

9、硬删除索引失效

硬删除(也称为物理删除)指的是直接从数据库表中删除数据行,硬删除操作可能导致数据库索引失效的原因通常包括以下几点:

1. 索引不再反映实际数据:

当你从表中硬删除数据时,索引中的数据不再反映实际表中的数据。这可能导致索引的统计信息不准确,从而影响查询优化器的决策,导致查询性能下降。

2. 索引分裂:

硬删除可能导致索引分裂(Index Split),即当一个索引页上的数据被删除时,可能会导致该页变得很空,而其他页可能变得很满。这样的分布可能导致索引的平衡性下降,影响查询性能。

3. 碎片化:

硬删除操作可能导致数据文件的碎片化,这会使得磁盘上的数据分布不连续,从而影响磁盘 I/O 性能。

4. 不再利用索引覆盖查询:

当一个表的数据经常被硬删除时,原本可以利用索引覆盖查询的查询可能不再有效,因为索引中的数据已经不再与实际数据匹配,这会导致查询需要回表(即从磁盘中读取数据行),增加了查询的开销。

5. 表和索引的统计信息不准确:

数据库系统通常会根据表中的数据分布和索引的使用情况来维护统计信息,以便于查询优化。硬删除可能导致这些统计信息不准确,从而影响查询计划的生成。

如何解决和避免索引失效:

  • 定期重建索引: 定期对表的索引进行重建操作可以帮助恢复索引的性能。MySQL 提供了 OPTIMIZE TABLE 命令用于重建表,可以帮助清理碎片,提高性能。
  • 使用软删除而非硬删除: 考虑使用软删除(添加一个标志位来标识数据是否被删除)而非硬删除,这样可以保持数据的完整性,同时避免硬删除导致的问题。

  • 定期收缩表空间: 如果使用的是 InnoDB 存储引擎,可以考虑定期使用 OPTIMIZE TABLE  table_name来收缩表空间,减少碎片。

  • 合理设计数据库模型: 合理的数据库设计和索引设计可以减少硬删除操作的频率,从而减轻硬删除带来的影响。

  • 避免频繁的删除操作: 尽量避免频繁的硬删除操作,考虑使用定期的数据归档和清理策略。

 

 

https://www.yuque.com/tulingzhouyu/sfx8p0/qnxql079alg2ghhz?singleDoc=

posted @ 2023-10-10 22:15  凡人半睁眼  阅读(85)  评论(0编辑  收藏  举报