索引

概述

索引 index 帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

索引结构

分类

B+树索引,最常见的索引类型,大部分引擎都支持。

Hash索引

R-tree索引

full-text全文索引。通过建立倒排索引,快速匹配文档的方式,mysql 5.6之后支持全文索引。

B树

多路平衡查找树,n阶B树,是一个节点最多可以存储n-1个key,n个指针,即n个范围

B+树索引

所有的元素都出现在叶子节点,根节点作为索引范围,叶子节点之间形成一个单向链表

image-20240301203807818

MySQL的B+树在原有基础上进行了优化,增加了一个指向相邻叶子节点的链表指针,形成了带有顺序的B+树,提高了区间的访问性能。即叶子节点是双向循环链表。

非叶子节点存储在一个块中

image-20240301204850388

Hash索引

类似HashMap的实现。没有顺序。普通查询只需检索一次。

为什么InnoDB存储引擎选择使用B+树索引结构?

  • 相对于二叉树,层级更少,搜索效率高

  • 相对于B树,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,保存同样的数据,只能增加树的高度,导致性能降低。

索引分类

主键索引,针对表中主键创建的索引,PRIMARY

唯一索引,避免同一个表中某数据列中的值重复,UNIQUE

常规索引。快速定位特定数据

全文索引。全为索引查找的数据为文本的关键词

InnoDB存储引擎中,根据索引的存储形式可以分为:

  • 聚集索引,将数据存储和索引放到一起,索引结构的叶子节点保存了行数据。必须有,且只有一个

  • 二级索引。将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键。可以存在多个。

举个例子,主键为id,二级索引了属性name,查询name=xx时,首先查询name索引,然后得到id,拿到id查询聚集索引

然后得到数据,这叫回表查询。

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引

  • 如果不存在主键,将使用第一个唯一索引作为聚集索引

  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引

索引语法

创建索引

如果只有一列,叫做单列索引,多列叫做组合索引

查看索引

删除索引

SQL性能分析

SQL执行频率

image-20240301214923589

类似上述输出

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10s)的所有SQL语句的日志

MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.conf)中配置如下信息:

show_query_log=1

long_query_time=2

profile详情

查看当前会话下历史查询所消耗的时间

查看某个query各个阶段消耗的时间

explain执行计划

explain 或者 desc命令获取MySQL如何执行Select语句的信息,包括在Select语句执行过程中表如何连接和连接的顺序.

explain查询结果各字段意义

  • id,select查询的序列号,表示查询执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。

  • select_type。

    • 常见的有simple,primary,union,subquery

  • type

    • 表示连接的类型,性能由好到差的连接类型为:Null,system、const、eq_ref、ref、range、index、all

    • 尽量向前优化

  • possible_keys

    • 可能用到的索引

  • key

    • 实际使用的索引,如果为Null,则没有使用索引

  • key_len

    • 表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。

  • rows

    • MySQL任务必须要啊执行查询的行数,在innodb引擎表中,这是一个估计值,可能并不总是准确的

  • filtered

    • 表示结果的行数占读取行数的百分比。

  • extra

    • 额外字段

索引使用

最左前缀法则

如果索引了多列多列,要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。

如果跳过某个列,索引将部分失效(后面的字段索引失效)

也即多列的索引,如果想要使用,必须将列全部都加上,否则会失效

索引失效

字符串不加单引号

索引将失效

模糊查询

如果仅仅是尾部模糊匹配,索引不会失效,如果是头部模糊匹配,索引会失效

or连接的条件

用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到

数据分布影响

如果MySQL评估使用全局扫描更快,则不会使用索引

这个很智能。

函数

当我们在查询条件中对索引列做了计算、函数、类型转换操作,这些情况下都会造成索引失效

SQL提示

在SQL语句中加入一些人为的提示来达到优化操作的目的

  • use index,只是建议,但可能不会使用,会进行内部评估

  • ignore index,同上,忽略

  • force index,同上,强制,一定会有

覆盖索引

尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select *

也即尽量明确查询结果的列名,并将其和索引中的列相同。这是为了尽量避免回表查询

对于主键索引来说,我们根据id查询,由于主键索引的叶子节点存储的全部数据,所以只需要一次

对于二级索引来说,叶子节点包括索引字段的值和主键id,那么这里如果查询的列不仅仅是索引的列,则会根据主键,去主键索引中查询,从而得到多余的列的数据。这样就多了一次查询索引。

前缀索引

当字段类型为字符串(varchar,text等时),有时候会需要索引很长的字符串,这让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

其中的n即为前缀长度。

n的大小选择,统计数据的特征,来决定n。

单列索引和联合索引的选择

在业务场景中,如果存在多个查询条件,考虑针对查询字段建立索引时,建议建立联合索引,而非单列索引。

索引设计原则

  • 针对数据量大,且查询比较频繁的表建立索引

  • 针对常作为查询条件(where)、排序、分组操作的字段建立索引

  • 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高

  • 如果时字符串类型,字段的长度较长,可以针对字段的特点,建立前缀索引

  • 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省空间,避免徽标,提高查询效率

  • 要控制索引数量,并不是多多益善,索引越多,维护代价越大

  • 如果索引列不能存储null值,请在建表时使用not null约束。这样可以在查询时,让mysql更好的选择索引

最后更新于

这有帮助吗?