【MySQL系列笔记】索引

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: MySQL的索引是一种数据结构,用于加快数据库查询操作的速度。它们通过在表中的一个或多个列上创建索引,可以快速定位到符合特定条件的行,从而提高查询效率。MySQL支持多种类型的索引,包括B树索引、哈希索引和全文索引。B树索引是最常用的索引类型,能够高效地支持范围查询和排序操作。创建和使用索引需要根据具体的查询需求和数据特点进行优化,避免过度索引或不正确索引导致的性能下降。此外,索引的维护也需要考虑到对数据库性能和存储空间的影响。因此,合理地创建、管理和使用索引是提高MySQL数据库性能的重要手段。

1. 概述

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

1.1. 特点

优点:

  • 提高数据检索的效率,降低数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

缺点:

  • 索引是一种数据结构,占用空间的,增加维护成本。
  • 降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低。

1.2. 语法

//创建索引
CREATE  [ UNIQUE | FULLTEXT ]  INDEX  index_name  
ON  table_name  ( index_col_name,... ) ;
//查看索引
SHOW  INDEX  FROM  table_name ;
//删除索引
DROP  INDEX  index_name  ON  table_name ;
//示例
create index index_dish_name on dish(name);
//创建联合索引
create index index_dish_name_price on dish(name,price);
show index from dish;
drop index index_dish_name_price on dish;

2. 结构

2.1. 概述

MySQL的索引是在存储引擎层实现的,常见的索引结构主要包含以下几种,重点关注B+Tree

索引结构

描述

B+Tree索引

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

Hash索引

底层数据结构是用哈希表实现的, 只有精确匹配索引列的查询才有效, 不支持范围查询

R-tree(空间索引)

空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少

Full-text(全文索引)

是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES

不同的存储引擎对于索引结构的支持情况。

索引

InnoDB

MyISAM

Memory

B+tree索引

Y

Y

Y

Hash 索引

N

N

Y

R-tree 索引

N

Y

N

Full-text

Y

Y

N

(其中Full-text在5.6版本之后,InnoDB才支持)

2.2. B-Tree

B-Tree,B树是一种多叉路衡查找树,多叉即每个节点有多个分支,每个节点储存索引和数据。其中五阶树最多有四个key,五个指针。

  • 5阶的B树,每一个节点最多存储4个key,对应5个指针。
  • 一旦节点存储的key数量到达5,就会裂变,中间元素向上分裂。
  • 在B树中,非叶子节点和叶子节点都会存放数据。

(B-Tree演示网站:B-Tree Visualization

2.3. B+Tree

B+Tree是B-Tree的变种

  • 所有的数据都会出现在叶子节点。
  • 叶子节点形成一个单向链表。
  • 非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。

2.4. MySQL的B+Tree

MySQL的默认引擎为InnoDB,结构为优化的B+Tree。如何优化呢?在每个叶子节点又增加了一个指向相邻叶子节点的指针,形成了双向循环列表

2.4.1. 为什么MySQL要选择B+Tree作为索引结构?

  • 相对于二叉树,层级更少,搜索效率高;
  • 对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
  • 相对Hash索引,B+tree支持范围匹配及排序操作;

2.4.2. B+Tree能保存多少数据呢?

假设:
一行数据大小为1k,一页中可以存储16行这样的数据。
InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节数为8。
当高度为2:
n*8+(n+1)*6=16*1024,算出n约为1170
1171*16=18736
当高度为3:
1171*1171*16=21939856

高度为2,可以理解为2页,每页字节大小为16*1024;指针页通过公式计算,可以算出最大可以存储约1170个key,即1171指针;数据页存储行数据,可以存储16行。

当索引高度为2时,存储的行数据为18000多行数据;当索引高度为3时,存储的行数据接近2200w行数据;

2.5. Hash

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。

如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可以通过链表来解决。

一些局限性:

  • 只能用于对等比较,不支持范围查询
  • 无法利用索引完成排序操作

3. 分类

3.1. MySQL索引分类

分类

含义

特点

关键字

主键索引

针对于表中主键创建的索引

默认自动创建, 只能有一个

PRIMARY

唯一索引

避免同一个表中某数据列中的值重复

可以有多个

UNIQUE

常规索引

快速定位特定数据

可以有多个

全文索引

全文索引查找的是文本中的关键词,而不是比较索引中的值

可以有多个

FULLTEXT

主要关注就是主键索引,一般情况下唯一的,自增的,非空的。

3.2. InnoDB索引分类

分类

含义

特点

聚簇索引

(Clustered Index)

将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据

必须有,而且只有一个

二级索引

(Secondary Index)

将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键

可以存在多个

聚簇索引选取规则:

  • 如果存在主键,主键索引就是聚簇索引。
  • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚簇索引。
  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚簇索引。

3.3. 其他索引概念

聚簇索引也叫聚集索引二级索引又叫聚簇索引辅助索引

回表查询: 这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。

覆盖索引:当查询二级索引返回的值已满足需求,不需回表查询(覆盖了聚集索引)。

联合索引:一个索引包含多个列。

前缀索引:当索引类型为字符串时,可取字符串的一部分前缀建立索引,查询效果基本一致,也达到节约索引空间,提高查询效率。


4. 索引建立原则

  1. 针对经常需要查询(status),数据量较大,查询慢(慢查询日志)的表建立索引。
  2. 针对于常作为查询条件(where),分组(group by),排序(order by)的操作字段建立索引。
  3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  4. 尽量选择非空列作为索引,在创建表时采取NOT NULL约束。
  5. 尽量使用联合索引,查询时,联合索引很多时候可以覆盖索引,避免回表,提高查询效率。
  6. 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  7. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。

5. SQL性能分析

5.1. 访问频次status

MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次:

-- session 是查看当前会话 ;
-- global 是查询全局数据 ; Com后面是七个下划线
SHOW  GLOBAL STATUS LIKE  'Com_______';

5.2. 慢查询日志slow_query_log

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


windows/linux

//查询慢日志的值
show variables like '%slow%';
show variables like 'slow_query_log';
//开启慢日志
set global slow_query_log = on;
//设置慢日志阈值时间
set global long_query_time = 2;
//慢日志地址
‪D:\Software\MySQL\mysql-8.0.31-winx64\data\xxx-slow.log


docker

//进入容器内部
docker exec -it mysql bash
//登录用户
mysql -uroot -proot
//执行查看慢日志
show variables like 'slow_query_log';
//查看慢日志中信息
cd /root/mysql/data
cat xxx-slow.log
//或找到mysql的数据卷挂载点,用系统编辑器打开
docker volume inspect mysql

5.3. 资源使用profiling

show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前MySQL是否支持profile操作:

//查看系统变量@@have_profiling,它的值取决于 MySQL 是否启用了查询性能分析
select @@have_profiling;
//查看Mysql系统变量@@profiling,它的值用于确定当前会话是否启用了查询性能分析
select @@profiling;
//开启profiling
set profiling = 1;
//查看每一条SQL的耗时基本情况
show profiles;
//查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query 16[query id];
//查看指定query_id的SQL语句CPU的使用情况
show profile  cpu for  query query_id;

(数据来源教程截图)

5.4. 执行流程explain

EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。

一般通过key_len判断SQL语句是否走索引,从而避免索引失效,进行SQL优化

//直接在select语句之前加上关键字 explain / desc
explain select * from dish where id = 10;

Explain 执行计划中各个字段的含义:

字段

含义

id

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

select_type

表示 SELECT 的类型,常见的取值有 SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等

type

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

possible_key

显示可能应用在这张表上的索引,一个或多个。

key

实际使用的索引,如果为NULL,则没有使用索引。

key_len

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

rows

MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。

filtered

表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好。


技术分享 | EXPLAIN 执行计划详解(2)--Extra

6. 索引失效

索引本质上还是一个提高搜索效率的工具,如何正确使用工具?可以从索引失效的场景出发,避免这些场景的出现,从而正确使用索引。索引失效情况分为以下几种:

6.1. 最左前缀法则

最左前缀法则指的是建立联合索引,查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。

通俗说,使用联合索引查询时,三列索引并排,where条件只使用第一列和第三列作为查询条件,那么第三列索引会失效。


举例:建立联合索引是采取三个字段,顺序为name,age,height

查询语句为select * from tb_student where  name = "xiaoming" and height = 170 and age = 15;

此时并不会产生索引失效

6.2. 范围查询

联合索引中,出现>或<范围查询,范围查询右侧的列索引失效。

在业务允许的情况下,尽可能的使用 >= 或 <= 这类的范围查询。

6.3. 列运算

对索引列进行函数运算

//索引失效
explain select * from tb_user where substring(phone,10,2) = '15';

6.4. 字符串不加引号

字符串类型字段使用时,不加引号,索引将失效。

//索引有效
explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0';
//索引失效
explain select * from tb_user where profession = '软件工程' and age = 31 and status = 0;

6.5. 模糊查询

模糊查询匹配头部会索引失效,匹配尾部不会。

//索引有效
explain select * from tb_user where profession like '软件%'; 
//索引失效
explain select * from tb_user where profession like '%工程'; 
//索引失效
explain select * from tb_user where profession like '%工%';

6.6. or连接条件

用or连接的两个查询字段,需要左右都有索引才会生效。

//索引失效
explain select * from tb_user where id = 10 or age = 23;
//索引失效
explain select * from tb_user where phone = '17799990017' or age = 23;
//由于age没有索引,所以即使id、phone有索引,索引也会失效。
//所以需要针对于age也要建立索引。

6.7. 数据分布影响

MySQL评估使用全表查询比索引快,那么索引失效。



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3天前
|
SQL 存储 关系型数据库
Mysql优化提高笔记整理,来自于一位鹅厂大佬的笔记,阿里P7亲自教你
Mysql优化提高笔记整理,来自于一位鹅厂大佬的笔记,阿里P7亲自教你
|
5天前
|
SQL 存储 关系型数据库
MySQL索引及事务
MySQL索引及事务
24 2
|
5天前
|
SQL 存储 关系型数据库
必知的 MySQL 索引失效场景【包括实践验证】,别再踩坑了!(下)
必知的 MySQL 索引失效场景【包括实践验证】,别再踩坑了!
22 2
|
5天前
|
SQL 关系型数据库 MySQL
必知的 MySQL 索引失效场景【包括实践验证】,别再踩坑了!(上)
必知的 MySQL 索引失效场景【包括实践验证】,别再踩坑了!
20 2
|
5天前
|
NoSQL 关系型数据库 MySQL
B+树 和 跳表 的结构及区别,不同的用途【mysql的索引为什么使用B+树而不使用跳表?】
B+树 和 跳表 的结构及区别,不同的用途【mysql的索引为什么使用B+树而不使用跳表?】
22 2
|
5天前
|
存储 算法 关系型数据库
MySQL索引详解
MySQL索引详解
15 0
|
5天前
|
存储 关系型数据库 MySQL
【MySQL系列笔记】分库分表
分库分表是一种数据库架构设计的方法,用于解决大规模数据存储和处理的问题。 分库分表可以简单理解为原来一个表存储数据现在改为通过多个数据库及多个表去存储,这就相当于原来一台服务器提供服务现在改成多台服务器组成集群共同提供服务。
28 8
|
5天前
|
存储 SQL 关系型数据库
完蛋!😱 我被MySQL索引失效包围了!
完蛋!😱 我被MySQL索引失效包围了!
|
5天前
|
SQL 存储 关系型数据库
MySQL的3种索引合并优化⭐️or到底能不能用索引?
MySQL的3种索引合并优化⭐️or到底能不能用索引?
|
5天前
|
存储 SQL 关系型数据库
MySQL索引,看这一篇就够了!
MySQL索引,看这一篇就够了!

相关产品

  • 云数据库 RDS MySQL 版