MySQL数据库:13、索引

MySQL数据库之索引

一、索引的概念

1、什么是索引

1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容

2)让获取的数据更有目的性,从而提高数据库检索数据的性能

2、索引的存储类型

​ MySQL中索引的存储类型有两种,即 BTree 和 Hash。

3、索引的实现

​ 索引是在存储引擎中实现的。(MySQL 的存储引擎有:InnoDB、MyISAM、Memory、Heap)

  • InnoDB / MyISAM 只支持 BTree 索引
  • Memory / Heap 都支持 BTree 和 Hash 索引

4、什么是存储引擎

存储引擎就是指 表的类型 以及 表在计算机上的存储方式。

5、索引的优缺点

  • 优点:

    • 提高数据的查询的效率(类似于书的目录)
    • 可以保证数据库表中每一行数据的唯一性(唯一索引)
    • 减少分组和排序的时间(使用分组和排序子句进行数据查询)
    • 被索引的列会自动进行分组和排序
  • 缺点:

    • 占用磁盘空间
    • 降低更新表的效率(不仅要更新表中的数据,还要更新相对应的索引文件)

二、索引的分类

1、普通索引 和 唯一索引

​ 普通索引:MySQL 中的基本索引类型,允许在定义索引的列中插入 重复值 和 空值

​ 唯一索引:要求索引列的值必须 唯一,但允许 有空值

​ 如果是组合索引,则列值的组合必须 唯一
​ 主键索引是一种特殊的唯一索引,不允许 有空值

2、单列索引 和 组合索引

​ 单列索引:一个索引只包含单个列,一个表可以有多个单列索引
​ 组合索引:在表的 多个字段 组合上 创建的 索引
​ 只有在查询条件中使用了这些字段的 左边字段 时,索引才会被使用(最左前缀原则)

3、全文索引

​ 全文索引 的类型为 fulltext
​ 在定义索引的 列上 支持值的全文查找,允许在这些索引列中插入 重复值 和 空值
​ 全文索引 可以在 char、varchar 和 text 类型的 列 上创建

4、空间索引

​ 空间索引 是对 空间数据类型 的字段 建立的索引

​ MySQL中的空间数据类型有4种,分别是 Geometry、Point、Linestring 和 Polygon

​ MySQL 使用 Spatial 关键字进行扩展,使得能够用创建正规索引类似的语法创建空间索引

​ 创建空间索引的列,不允许为空值,且只能在 MyISAM 的表中创建。

5、前缀索引

​ 在 char、varchar 和 text 类型的 列 上创建索引时,可以指定索引 列的长度

三、索引加快查询的本质

1、primary key
2、unique key
3、index key

1.上述的三个key都可以加快数据查询
2.primary key和unique key除了可以加快查询本身还自带限制条件而index key很单一就是用来加快数据查询
3.外键不属于索引键的范围 是用来建立关系的 与加快查询无关

	id int primary key auto_increment,
 	name varchar(32) unique,
  	province varchar(32)
 	age int
 	phone bigint

	select name from userinfo where phone=18818888888;  # 一页页的翻
	select name from userinfo where id=99999;  # 按照目录确定页数找

索引可以加快数据查询 但是会降低增删的速度
通常情况下我们频繁使用某些字段查询数据
为了提升查询的速度可以将该字段建立索引

聚集索引(primary key)
主键、主键索引
辅助索引(unique,index)
除主键意外的都是辅助索引,辅助索引其实本质上也是用的聚集索引的数据来查询的(用的主键的数据)

覆盖索引

select name from user where name='jason';

所谓覆盖索引就是条件中的字段名和查看的字段名称相同

非覆盖索引

select age from user where name='jason';

四、索引的结构

​ MySQL 索引 的数据结构可以分为 BTree 和 Hash 两种,BTree 又可分为 BTree 和 B+Tree。

1、Hash

​ hash:也可称为‘二叉树’

​ 使用 Hash 表存储数据,Key 存储索引列,Value 存储行记录或行磁盘地址。

Hash 只支持等值查询(“=”,“IN”,“<=>”),不支持任何范围查询(原因在于 Hash 的每个键之间没有任何的联系),Hash 的查询效率很高,时间复杂度为 O(1)。

img

2、BTree

属于多叉树,又名多路平衡查找树。

MySQL的数据是存储在磁盘文件中的,查询数据时需要先把磁盘中的数据加载到内存中,磁盘IO操作非常耗时,所以我们优化的重点就是尽量减少磁盘IO操作,所以,我们应当尽量减少从磁盘中读取数据的次数。另外,从磁盘中读取数据时,都是按照磁盘块来读取的,并不是一条一条的读。如果我们能把尽量多的数据放进磁盘块中,那一次磁盘读取操作就会读取更多数据,那我们查找数据的时间也会大幅度降低。

如果我们用树这种数据结构作为索引的数据结构,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块。我们都知道平衡二叉树可是每个节点只存储一个键值和数据的。那说明什么?说明每个磁盘块仅仅存储一个键值和数据!那如果我们要存储海量的数据呢?

可以想象到二叉树的节点将会非常多,高度也会极其高,我们查找数据时也会进行很多次磁盘IO,我们查找数据的效率将会极低!

为了解决平衡二叉树的这个弊端,B树应运而生, B树是一种多叉平衡查找树,主要的特点是:

  • BTree 的节点存储多个元素( 键值 - 数据 / 子节点 的地址)
  • BTree 节点的键值按 非降序 排列
  • BTree 所有叶子节点都位于同一层(具有相同的深度)

下面模拟下查找key为27的data的过程:

img

存在的一些问题:

  • B树中每个节点中包含key值以及data值,而每一个节点的存储空间是有限的(MySQL默认16K),如果data中存放的数据较大时,将会导致每个节点能存储的key的数量很小,所以当数据量很多,且每行数据量很大的时候,同样会导致树的高度变得很高,增大查询时的磁盘IO次数,进而影响查询效率。
  • 不支持范围查询的快速查找,而在实际的应用中,数据库范围查询的频率非常高,以下的一种情况是我查找10和35之间的数据,查找到15之后,需要回到根节点重新遍历查找,需要从根节点进行多次遍历,查询效率有待提高。

3、B+Tree

只有叶子节点才会存放真正的数据 其他节点只存放索引数据

对比B树和B+树,我们发现二者主要存在以下几点不同的地方:

  • 数据都存放在叶子节点中
  • 非叶子节点只存储键值信息,不再存储数据
  • 所有叶子节点之间都有一个指针,指向下一个叶子节点,而且叶子节点之间使用双向指针连接,最底层的叶子节点形成了一个双向有序链表

等值查询

下面模拟下查找key为9的data的过程:

img

范围查询

下面模拟下查找key的范围为9到26这个范围的data的过程:

img

从上面的结果,我们可以知道B+树作为索引结构带来的好处:

  • 磁盘IO次数更少
  • 数据遍历更为方便
  • 查询性能更稳定

由于B+树优秀的结构特性,在MySQL中,存储引擎MyISAM和InnoDB的索引就采用了B+树的数据结构。

B*树

B*叶子节点和枝节点都有指向其他节点的指针

ps:

  • 辅助索引在查询数据的时候最会还是需要借助于聚集索引
  • 辅助索引叶子节点存放的是数据的主键值
  • 有时候就算采用索引字段查询数据 也可能不会走索引!!!

五、索引失效的情况

1.前导模糊查询不能利用索引(like '%XX'或者like '%XX%')

2.如果mysql估计使用全表扫描要比使用索引快,则不使用索引

3.OR前后存在非索引的列,索引失效

如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)

要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引

4.普通索引的不等于不会走索引;如果是主键,则还是会走索引;如果是主键或索引是整数类型,则还是会走索引

5.组合索引最左前缀

    如果组合索引为:(name,email)

    name and email -- 使用索引

    name -- 使用索引

    email -- 不使用索引

6.is null可以使用索引,is not null无法使用索引

最好在设计表时设置NOT NULL约束,比如将INT类型的默认值设为0,将字符串默认值设为''。

7.计算、函数导致索引失效另外一种情况

#使用到了索引

explain select * from student_info where name like 'li%';

#未使用索引,花费时间更久

explain select * from student_info where LEFT(name,2)='li';

扩展:

如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引

#不会使用name的索引

explain select * from student_info where name=123;

#使用到索引

explain select * from student_info where name='123';

如上,name字段是VARCAHR类型的,但是比较的值是INT类型的,name的值会被隐式的转换为INT类型再比较,中间相当于有一个将字符串转为INT类型的函数。这也相当于是函数导致的索引失效。

8.字符集不统一

统一使用utf8mb4( 5.5.3 版本以上支持 ) 兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的 字符集 进行比较前需要进行 转换 会造成索引失效。。

ps:最好能记三个左右的特殊情况

posted @ 2022-11-29 21:18  kangshong  阅读(121)  评论(0编辑  收藏  举报