【MySQL进阶篇】索引

1、索引概述

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

优势劣势
提高数据检索效率索引列也是要占用空间的
通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATA、DELETE时,效率降低

2、索引结构

MySQL的索引是在引擎层实现的,不同的存储引擎有不同的结构,主要包括以下几种:

索引结构描述
B+tree索引最常见的索引类型,大部分引擎都支持B+树索引
Hash索引底层数据结构使用哈希表来实现的,只有精确匹配索引列的查询才有效,不支持范围查询
R-tree索引(空间索引)空间索引是MyISAM引擎的一种特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text索引(全文索引)是一种通过建立倒排索引,快速匹配文档的方式,类似于Lucene,Solr,ES
索引InnoDBMyISAMMemory
B+tree索引支持支持支持
Hash索引不支持不支持支持
R-tree索引不支持支持不支持
Full-text索引支持支持不支持

 我们平常说的索引,如果没有特别指明,都是指B+tree结构组织的索引

不选择二叉树的原因:顺序插入时,会形成一个链表,查询性能大大降低。大量数据情况下,层级较深,检索速度慢;而红黑树本质上还是一个二叉树,在大量数据的情况下,层级越深,检索速度越慢。

· B-tree(多路平衡查找树)

以一颗最大度数(max-degree)为5(5阶)的B-tree为例(每个节点最多存储4个key,5个指针)

树的度数指的是一个节点的子节点个数

插入 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 数据为例

可以在这个网站自行尝试: B-Tree Visualization (usfca.edu)

· B+tree

以一颗最大度数(max-degree)为4(4阶)的B+tree为例:

插入 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 数据为例

 具体动态操作参考网站:B+ Tree Visualization (usfca.edu)

相对于B-tree的区别:

1、所有的数据都会出现在叶子节点上(非叶子节点仅仅起到索引的作用)

2、叶子节点形成一个单向链表

MySQL索引数据结构对经典的B+tree进行了优化。在原B+tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+tree,提高区间访问的性能。

· Hash

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可以通过链表来解决。

hash索引的特点:

1、hash只能用于对等比较(=,in)不支持范围查询(between,>,<,....)

2、无法利用索引完成排序操作

3、查询效率高,通常只需要一次检索就可以了,效率通常要高于B+tree索引

在MySQL中,支持hash索引的是Memory引擎,而InnoDB中具有自适应hash功能,hash索引时存储引擎根据B+tree索引在指定条件下自动构建的。

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

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

2、相对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低(并且在B+tree索引中形成了一个双向链表,便于范围搜索和排序);

3、相对于hash索引,B+tree索引支持范围匹配和排序操作。

3、索引分类

分类含义特点关键字
主键索引针对于表中主键创建的索引默认自动创建,只能有一个PRIMARY
唯一索引避免同一个表中某数据列的值重复可以有多个UNIQUE
常规索引快速定位特定数据可以有多个
全文索引全文索引查找的是文本的关键词,而不是比较索引中的值可以有多个FULLTEXT

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

分类含义特点
聚集索引(Clustered Index)将数据存储与索引放到了一起,索引结构的叶子节点保存了行数据必须有,而且只有一个
二级索引(secondary Index)将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键可以存在多个

 聚集索引选取规则:

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

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

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

1、以下SQL语句,那个执行效率高?为什么?

select * from user where id=10;

select * from user where name='张三';

备注:id为主键,name字段创建的有索引

第一个一次索引扫描就完成了,而第二种情况,是先到name字段的二级索引去查找的,查找到对应的id值再根据id值到聚集索引当中去查询,涉及到回表查询。因此根据id索引执行效率更高。

2、InnoDB主键索引的B+tree高度为多高?

假设一行数据大小为1k,一页中可以存放16行这样的数据。InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节为8。

假设高度为2:

n*8+(n+1)*6=16*1024,算出n约为1170,因此有1171个指针

能够存储数据:1171*16=18736

高度为3:

能够存储数据:1171*1171*16=21939856 

4、索引语法

· 创建索引

CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(index_col_name,...);

· 查看索引

SHOW INDEX FROM table_name; 

· 删除索引

DROP INDEX index_name ON table_name;  

5、SQL性能分析

· SQL执行频率

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

show global status like 'com_______';

 · 慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认是10秒)的所有SQL语句的日志。MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

#开启MySQL慢日志查询开关

slow_query_log=1;

#设置慢查询的时间为两秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志

long_query_time=2

配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息/var

/lib/mysql/localhost-slow.log。

#慢查询日志
set global slow_query_log ='ON';
set long_query_time=2;
show variables like 'slow_query_log_file'; 
select * from emp;
+----+--------+------+----------+--------+------------+-----------+---------+
| id | name   | age  | job      | salary | entrydate  | managerid | dept_id |
+----+--------+------+----------+--------+------------+-----------+---------+
|  1 | 金庸   |   66 | 总裁     |  20000 | 2000-01-01 |      NULL |       5 |
|  2 | 张无忌 |   20 | 项目经理 |  12500 | 2005-12-05 |         1 |       1 |
|  3 | 杨逍   |   33 | 开发     |   8400 | 2000-11-03 |         4 |       1 |
|  4 | 韦一笑 |   48 | 开发     |  11000 | 2002-02-05 |         4 |       1 |
|  5 | 常遇春 |   43 | 开发     |  10500 | 2004-09-07 |         2 |       1 |
+----+--------+------+----------+--------+------------+-----------+---------+
5 rows in set (0.00 sec)
 select sleep(3);
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.01 sec)

 · profile详情

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

SELECT @@have_profiling;

默认profiling是关闭的,可以通过set语句在session/global级别开启profiling;

SET profiling=1; 

执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:

#查看每一条SQL的耗时基本情况

show profiles;

#查看指定query_id的SQL各个阶段的耗时情况

show profile for query query_id;

#查看指定query_id的SQL语句的CPU的使用情况

show profile cpu for query query_id; 

· explain执行计划

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

语法:

EXPLAIN/DESC SELECT 字段列表 FROM 表名 WHERE 条件; 

 explain select * from tb_user where id=1;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | tb_user | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

EXPLAIN执行计划个字段含义;

        id:

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

explain select * from student s where s.id in(select studentid from student_course sc where sc.id=(select id from course c where c.name='mysql'));

        select_type:

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

        type:

表示连接类型,性能由好到差的连接类型为NULL(不访问任何表)、system(系统表)、const(主键或唯一索引)、eq_ref(非唯一索引)、ref、range、index、all。

        possible_key:

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

        key:

实际用到的索引。

        key_len:

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

        rows:

MySQL认为必须要执行查询的行数,在InnoDB引擎的表中,可能并不总是准确的

        filtered:

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

6、索引使用

· 最左前缀法则

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

show index from tb_user;
create unique index tb_user_phone on tb_user(phone);
create index tb_user_age_gender_pro on tb_user(age,gender,profession);
select * from tb_user where age=55 && gender=1;
explain select * from tb_user where age=55 && gender=1 &&profession='软件工程';
explain select * from tb_user where age=55;
#仅仅在大数据量的情况下

· 范围查询

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

索引失效的情况:

· 索引列运算

不要再索引列上进行运算,索引将会失效

explain select * from tb_user where phone='15538655111';
#用到了索引:tb_user_phone
explain select * from tb_user where substring(phone,10,2)='11';
#索引失效,因为我们进行了函数运算

· 字符串不加引号

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

explain select * from tb_user where phone=15538655111;
#可以查询出信息,但不会用到索引

· 模糊查询

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

explain select * from tb_user where phone like '%11';
#头部模糊匹配,索引失效
explain select * from tb_user where phone like '11%';
#索引不会失效

 · or连接的条件

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

· 数据分布影响

如果MySQL评估使用索引比全表更慢,则不使用索引。

· SQL提示

explain select * from tb_user where profession='软件工程';
create index tb_user_pro on tb_user(profession);
explain select * from tb_user where profession='软件工程';
#一个是单列索引一个是联合索引,MySQL优化器会自动选择结果

SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

use index:

explain select * from use index(index_name) where 条件; 

ignore index:

 explain select * from ignore index(index_name) where 条件; 

force index:

explain select * from force index(index_name) where 条件;  

· 覆盖索引

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

explain select id,profession from tb_user where profession='软件工程';

额外信息出现using where、using index性能更高;而出现using condition性能更低(MySQL版本不同所展示的信息也不同)

 using condition:查找使用了索引但需要回表查询数据

usi:ng where、using index:查找使用了索引,但是需要的数据都在索引列中能找到,不需要回表查询数据。

之所以避免使用select *是因为很容易出现覆盖索引导致回表查询(除非及其他字段建立联合索引),从而降低查询性能

思考:一张表,有四个字段(id,username,password,status)由于数据量大,需要对SQL语句优化,如何才能最优: 

select id,username,password from tb_user where username='test';

最佳方案是username于password建立一个联合索引,能够大量减少回表查询。 

· 前缀索引

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

语法:

create index idx_xxxx on table_name(column(n)); 

前缀长度:

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

select count(distinct email)/count(*) from tb_user;

select count(distinct substring(email,1,5))/count(*) from tb_user;

· 单列索引与联合索引

 单列索引:即一个索引只包含单个列。

联合索引:即一个索引包括了多个列。

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

7、索引设计原则

1. 针对于数据量较大,且查询比较频繁的表建立索引。
2. 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4. 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
7. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/801178.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode算法题(链表的中间节点+返回倒数第k个节点+合并两个有序链表)

题目1&#xff1a; 本题力扣链接&#xff1a;https://leetcode.cn/problems/middle-of-the-linked-list/solutions/164351/lian-biao-de-zhong-jian-jie-dian-by-leetcode-solut/ 思路1&#xff1a;单指针法 首先我们对链表进行遍历&#xff0c;记录链表的总长度N&#xff0c;…

STM32 - FLASH 笔记

STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&#xff0c;通过闪存存储器接口&#xff08;外设&#xff09;可以对程序存储器和选项字节进行擦除和编程 读写FLASH的用途&#xff1a; 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 通过在程序…

《系统架构设计师教程(第2版)》第11章-未来信息综合技术-06-云计算(Cloud Computing) 技术概述

文章目录 1. 相关概念2. 云计算的服务方式2.1 软件即服务 (SaaS)2.2 平台即服务 (PaaS)2.3 基础设施即服务 (IaaS)2.4 三种服务方式的分析2.4.1 在灵活性2.4.2 方便性方 3. 云计算的部署模式3.1 公有云3.2 社区云3.3 私有云3.4 混合云 4. 云计算的发展历程4.1 虚拟化技术4.2 分…

MQTT服务端EMQX开源版安装和客户端MQTTX介绍

一、EMQX是什么 EMQX 是一款开源的大规模分布式 MQTT 消息服务器&#xff0c;功能丰富&#xff0c;专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条&#xff0c;单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息&#xff0c;同时保证毫秒…

3d导入模型后墙体变成黑色?---模大狮模型网

在展览3D模型设计领域&#xff0c;技术和设计的融合通常是创意和实现之间的桥梁。然而&#xff0c;有时设计师们会遇到一些技术上的挑战&#xff0c;如导入3D模型后&#xff0c;墙体却突然变成了黑色。这种问题不仅影响了设计的视觉效果&#xff0c;也反映了技术应用中的一些复…

二叉搜索树的实现[C++]

文章目录 搜索二叉树概念二叉搜索树的功能查找 实现搜索二叉树节点的定义建立搜索二叉树接口插入搜索打印删除 总结 今天本堂主来一起讨论下什么是搜索二叉树&#xff0c;和如何实现二叉搜索树 搜索二叉树 那么二叉搜索树似乎如何实现搜索呢&#xff1f;二叉搜索树和普通二叉…

Android Media3 技术应用详解

1、音视频基础 一个简单的音视频链路如下&#xff1a; 1&#xff09;采集&#xff0c;音视频经过采集后分别生成音频流和视频帧&#xff0c;音频是流式的物理上没有帧的概念&#xff0c;但为了数据处理的方便实际数据处理中引入了音频帧的概念&#xff0c;一般中间插入静音数据…

py-automapper非常详细的详解——看完不会用你打我

一、py-automapper简介 开发过.Net项目的工程师大部分都用过AutoMapper来进行对象映射&#xff0c;py-automapper就是本第三方包的Python版本。我不太确定Python版本是否覆盖了.Net版本的所有功能&#xff0c;但常用功能都实现了&#xff1a;对象映射、空值处理、属性特殊处理…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-15 SPI接收程序设计

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

【漏洞复现】WordPress——Recall——SQL注入(CVE-2024-32709)

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 WordPress是一款免费开源的内容管理系统(CMS)&#xff0c;最初是…

Java 反射用法和8道练习题

目录 一、什么是反射二、反射的核心接口和类三、测试代码 Bean 类和目录结构Person 类代码目录结构 四、获取 Class 对象五、获取构造方法 Constructor 并使用六、获取成员变量 Field 并使用七、获取成员方法 Method 并使用八、练习1. 使用反射获取String类的所有公有方法&…

虚拟机:VMware功能,安装与使用

目录 一、虚拟机介绍 二、VMware 1.介绍 2.安装 &#xff08;1&#xff09;根据提示按步骤安装​编辑 &#xff08;2&#xff09;更改软件的安装地址​编辑 &#xff08;3&#xff09;根据自己的需求选择是否需要软件更新​编辑 &#xff08;4&#xff09;根据需求选择…

3. JavaSE ——【逻辑运算符】

&#x1f680; 开场白 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&…

Billu_b0x靶机

信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令&#xff1a; arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令&#xff1a; nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…

【深度学习】PyTorch框架(2):激活函数

1.引言 在文中&#xff0c;我们将深入探讨流行的激活函数&#xff0c;并分析它们在神经网络优化特性中的作用。激活函数在深度学习模型中扮演着至关重要的角色&#xff0c;因为它们为网络引入了非线性特性。尽管文献中描述了众多的激活函数&#xff0c;但它们并非一视同仁&…

北京交通大学《深度学习》专业课,实验2-前馈神经网络

1. 源代码 见资源“北京交通大学《深度学习》专业课&#xff0c;实验2-前馈神经网络” 2. 实验内容 &#xff08;1&#xff09;手动实现前馈神经网络解决上述回归、二分类、多分类任务 分析实验结果并绘制训练集和测试集的loss曲线 &#xff08;2&#xff09;利用to…

发电机保护屏的工作原理和组成

发电机保护屏的工作原理和组成 发电机保护屏的工作原理是通过监测发电机的电气参数和运行状态&#xff0c;‌一旦发现异常或故障&#xff0c;‌及时采取相应的保护措施&#xff0c;‌以确保发电机的安全运行。‌ 发电机保护屏通常包含各种传感器、‌保护继电器和控制…

Golang | Leetcode Golang题解之第231题2的幂

题目&#xff1a; 题解&#xff1a; func isPowerOfTwo(n int) bool {const big 1 << 30return n > 0 && big%n 0 }

整数或小数点后补0操作

效果展示&#xff1a; 整数情况&#xff1a; 小数情况&#xff1a; 小编这里是以微信小程序举例&#xff0c;代码通用可兼容vue等。 1.在utils文件下创建工具util.js文本 util.js页面&#xff1a; // 格式…

docker desktop历史版本安装

1.安装choco Windows安装 choco包管理工具-CSDN博客 2.通过choco安装 下面例子为安装旧版2.3.0.2,其它版本类似 Chocolatey Software | Docker Desktop 2.3.0.2 https://download.docker.com/win/stable/45183/Docker%20Desktop%20Installer.exe choco install docker-des…