MySQL进阶 索引

一、概述

索引是数据库中用于加速数据检索的数据结构,类似于书籍的目录。通过创建索引,可以显著减少查询时需要扫描的数据量,提高查询效率。MySQL支持多种索引类型,适用于不同的场景和需求。

二、索引结构

1、B+Tree

最常用的索引类型,适用于全值匹配、范围查询和前缀匹配。

下面以一颗最大度数为4的B+Tree为例

可以观察到,与BTree不同,B+Tree的数据全在叶子节点,非叶子节点只用于存储键值,不存储数据,因此节点更小。更适合磁盘存储。同样,因为数据都在叶子节点,查找每个数据所需要的时间相差不大,具有更稳定的性能。在MySQL中,对传统B+Tree的结构进行了优化,更利于查询,如下图

在原B+Tree的基础上,加上了一个指向邻向叶子节点的指针,形成了带有顺序指针的B+Tree,使区间访问的性能更佳。

2、哈希索引

基于哈希表实现,对于主键等值查询速度比B+Tree快,但因为其不支持范围查询,因此其泛用性相对于B+Tree不高。

思考:为什么InnoDB存储选择使用B+Tree索引结构

(1)相对于二叉树,层级更少,搜索效率高;

(2)对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;

三、索引分类

在InnoDB中,索引根据存储形式,又分为以下两种

聚集索引(根据id主键)

二级索引(根据name)

四、索引语法

1、创建索引

sql 复制代码
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(index_col_name,...);

ON前的字段为构建的索引名,括号内的字段为构建的索引在当前数据库中的字段名。

2、查看索引

sql 复制代码
SHOW INDEX FROM table_name;

3、删除索引

sql 复制代码
DROP INDEX index_name ON table_name;

五、性能分析

1、SQL执行频率

为了辅助创建索引,MySQL提供了一些命令可以用于查询当前服务器的INSERT、DELETE、UPDATE、SELECT指令的执行频次

语法

sql 复制代码
SHOW [session|global] STATUS;

选择session为查询当前会话的执行频次,global为全局的执行频率。

2、慢查询日志

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

MySQL的慢查询日志默认没有开启。需要在MySQL的配置文件配置以下信息(/etc/my.cnf)

慢查询日志的位置位于/var/lib/mysql/localhost-slow.log文件下,注意,这里是本地虚拟机下的文件名,若在服务器中localhost会变为该服务器ip。

3、show profiles命令

show profiles命令可以帮助我们在做SQL优化时了解时间都耗费到哪个位置了。

通过have_profiling参数,可以知道当前数据库是否支持此操作。

若为NO,可以通过set profiling=1指令开启。

具体指令

show profiles可以获取当前会话执行的所有sql并展示其耗时情况,每条sql都有对应id,用于后两个指令。

4、explain执行计划

explain执行计划是构建索引时常用的指令。这个指令可以获取到MySQL如何执行SELECT语句的信息。

explain执行计划各字段含义

六、索引使用

假设目前有一张学生表,有id,name,course,age,grade,字段

sql 复制代码
SELECT * FROM student WHERE name='张三';

如果该表内有1000万条数据,执行此查询语句可能需要20s。

sql 复制代码
CREATE INDEX idx_student_name on student(name);

执行该语句为name构建索引后,再次执行该SELECT语句,我们能观察到时间已经压缩到了几毫秒。

此时使用的为单列索引。

如果使用的是联合索引,则需要遵守最左前缀原则。

*最左前缀法则:查询从索引的最左列开始(构建联合索引时括号内的第一个字段必须存在),并且不跳过索引中的列。

如果跳过某一列,索引将部分失效(跳过的那一列后面的索引都失效),所以构建联合索引时,需要注意括号内字段的顺序。

例:

sql 复制代码
CREATE INDEX idx_student_name_age_coruse on student(name,age,course);
sql 复制代码
SELECT * FROM student where age = 1 AND course = '20260101';

此次SELECT语句就没有使用到索引,因为构建索引时最左边的字段name没有出现。where语句后字段出现的顺序不重要,但最左字段必须出现。

*索引列上不能出现运算操作,否则索引失效。例如substring(name,10)等操作。

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

*SQL提示语法

SQL提示就是在SQL语句中加入一些人为的提示起到优化操作的目的。

where中使用了>或<符号会导致此处和此处后字段的索引失效,所以尽量使用>=或<=来筛选数据。

⭐覆盖索引&回表查询

查询时尽量不使用 * 作为条件,回顾上图

此处构建了name的单列索引,此时通过name查询能获取name和id的值,若是查询条件中含有这两个之外的字段,就会发生回表查询,即通过获取的id值在聚集索引中获取一整行(row)的值,然后再输出。直接在索引建的二级索引中获取查询条件中的所有数据的查询方法叫覆盖查询。

不止单索引可以触发覆盖查询,联合索引也行,因此在建立索引时尽量使用联合索引,配合覆盖查询使用,可以大大提升查询效率。

尽量使用覆盖查询(查询使用了索引,并且所需要返回的列在该索引中能够全部找到)。

⭐前缀索引

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

语法

sql 复制代码
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(index_col_name(n),...);

括号内的n为需要截取的前缀长度。

n值可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

例如 course 中n为5时的选择性

sql 复制代码
SELECT count(distinct substring(course,5))/count(*) from student;

多条件联合查询时,MySQL优化器会根据使用哪个索引的效率更高选择使用的索引。

七、索引的设计原则

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

2.针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。

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

  2. 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。

  3. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。

  4. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。

  5. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

相关推荐
晚霞的不甘20 分钟前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
市场部需要一个软件开发岗位40 分钟前
JAVA开发常见安全问题:纵向越权
java·数据库·安全
海奥华243 分钟前
mysql索引
数据库·mysql
2601_949593652 小时前
深入解析CANN-acl应用层接口:构建高效的AI应用开发框架
数据库·人工智能
javachen__2 小时前
mysql新老项目版本选择
数据库·mysql
Dxy12393102162 小时前
MySQL如何高效查询表数据量:从基础到进阶的优化指南
数据库·mysql
Dying.Light2 小时前
MySQL相关问题
数据库·mysql
蜡笔小炘2 小时前
LVS -- 利用防火墙标签(FireWall Mark)解决轮询错误
服务器·数据库·lvs
韩立学长2 小时前
基于Springboot泉州旅游攻略平台d5h5zz02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
Re.不晚3 小时前
MySQL进阶之战——索引、事务与锁、高可用架构的三重奏
数据库·mysql·架构