什么是索引
MySQL的索引(Index)是一种用于提高数据库表查询效率的数据结构。它类似于书籍的目录,能够显著加快数据的检索速度。索引通过创建一个额外的、有序的数据结构(如B树、哈希表等),使得MySQL能够快速定位到表中的特定记录,而无需扫描整个表。这些数据结构就是索引。
索引的作用
在执行查询时,MySQL可以利用索引快速定位到包含所需数据的位置,而不是逐行扫描整个表。因此,索引可以显著减少查询的响应时间,加快数据库的查询速度。
索引的结构
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:
索引结构 | 描述 |
---|---|
B+Tree索引 | 最常见的索引类型,大部分引擎都支持 B+ 树索引 |
Hash索引 | 底层数据结构是用哈希表实现的, 只有精确匹配索引列的查询才有效, 不支持范围查询 |
R-tree(空间索引) | 空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少 |
Full-text(全文索引) | 是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES |
B树数据结构
B-Tree
B树是一种自平衡的多路查找树,相对于二叉树,B树的每个节点都可以有多个分支,从而降低查找的时间复杂度。
B树的每个节点都可以存放数据。对于一个n阶的B树,每个节点最多可以存储n-1个key,最多有n个指针。
B+Tree
与B树相比,B+树主要有以下3个特点,更适合作为数据库的索引:
- B+树的所有数据均在叶子节点上。
- 叶子节点形成了一个单向链表。
- 非叶子节点仅仅起到索引数据的作用。
B+Tree的磁盘读写代价更低 B+Tree的内部节点并没有指向关键字具体信息的指针。因此其内部节点相对BTree更小,如果把所有同一内部节点的关键字存放在同一个盘块中,那么盘块所能容纳的关键字数量也越多。一次性读取到内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了
B+Tree的查询效率更加稳定 由于非叶子节点不是最终指向文件内容的节点,而是叶子节点中关键字的索引,所以任何关键字的查找都必须走一条从根节点到叶子节点的路。所有关键字的路径长度相同,导致每个数据的查询效率相当。
在MySql中,索引数据结构对经典B+Tree进行了优化,在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提供了区间访问的性能。利于排序(双向链表) 。
索引的分类
在MySQL数据库,将索引的具体类型主要分为以下几类:主键索引、唯一索引、常规索引、全文索引。
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对于表中主键创建的索引 | 默认自动创建, 只能有一个 | PRIMARY |
唯一索引 | 避免同一个表中某数据列中的值重复 | 可以有多个 | UNIQUE |
常规索引 | 快速定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键词,而不是比较索引中的值 | 可以有多个 | FULLTEXT |
而在在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:
分类 | 含义 | 特点 |
---|---|---|
聚集索引(Clustered Index) | 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 | 必须有,而且只有一个 |
二级索引(Secondary Index) | 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 | 可以存在多个 |
- 如果存在主键,主键索引就是聚集索引。
- 如果不存在主键,将会使用第一个唯一索引作为聚集索引。
- 如果表没有主键,或者没有一个合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
语法
创建索引
当表查询多,增删改少时建议添加索引,给where中经常出现的列,order by 排序的列,select查询的列添加索引。
CREATE [UNIQUE(唯一索引) | FULLTEXT(全文索引)] INDEX index_name ON table_name(
index_col_name,.....);
查看索引
SHOW INDEX FROM table_name;
删除索引
DROP INDEX index_name ON table_name;
sql执行计划
SQL执行计划描述了数据库如何访问数据以执行查询,包括使用的索引、表连接顺序、数据排序和聚合方法等。
语法:explain + sql语句
里面字段的意思是:
字段 | 解释 |
---|---|
select_type | 查询的类型 |
table | 显示数据关于哪张表 |
partitions | 匹配的分区 |
type | 连接类型 |
possible_keys | 显示可能应用的索引 |
key | 实际使用的索引 |
ref | 显示索引的那一列被用于查找值 |
其中,type是重要的列,显示连接使用了哪种类型,从好到坏的连接类型为。
system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >ALL
最左匹配原则
当使用复合索引进行查询时,数据库引擎会从索引的最左列开始匹配查询条件。换句话说,为了有效利用复合索引,查询条件中必须包含索引的最左列(第一列),并且可以按照索引中列的顺序连续匹配(但不一定非得全部匹配)。如果查询条件跳过了索引的最左列,或者没有按照索引列的顺序进行匹配,那么数据库引擎可能无法使用该复合索引来加速查询,从而导致查询性能下降。
示例:
我创建了一个索引
只有当查询条件出现了包含索引的最左列才使用了索引。其他时候出现了索引失效。
索引失效
索引失效通常指的是数据库查询无法有效利用索引,从而导致查询性能下降的现象。
索引失效的原因有很多:
- 模糊查询的前导通配符:当使用LIKE操作符进行模糊查询时,如果通配符(%)位于查询字符串的前面(如LIKE ‘%abc’),索引将无法被有效利用,因为数据库需要扫描整个索引或表来查找匹配的行。
- 未使用索引字段进行过滤:如果查询条件没有使用到创建的索引字段,数据库则不会使用该索引。因此,在构建查询时,应确保查询条件与索引字段相匹配。
- 数据类型不匹配:当查询条件的数据类型与索引字段的数据类型不匹配时,索引也会失效。例如,如果索引字段是整数类型,而查询条件中使用了字符串类型的值,那么索引将不会被使用。
- 对索引列进行函数操作:如果在查询条件中对索引字段进行了函数操作(如LOWER(column)、YEAR(created_at)等),索引可能会失效。这是因为数据库无法直接使用索引来查找经过函数处理后的值。
- OR运算:在OR运算中,如果其中一个条件使用了索引,而另一个条件没有使用索引,整个查询可能会导致索引失效。这是因为数据库可能无法有效地利用索引来加速查询。
- 使用NOT运算:NOT运算通常会使索引失效,因为数据库无法使用索引来高效处理NOT运算。
- 范围查询后的索引失效:在复合索引中,如果第一个列(或前导列)使用了范围查询(如>、<、BETWEEN等),那么后续列上的索引可能无法被有效利用。
- 隐式类型转换:当查询条件存在隐式类型转换时,索引也可能失效。例如,如果数据库中的ID字段是整数类型,但在查询中使用了字符串类型的值(如'123'),则可能发生隐式类型转换,导致索引失效。