MySQL进阶2 - 索引

MySQL进阶1 - 索引

  • 1. 索引概述
  • 2. 索引结构
    • 2.1 二叉树
    • 2.2 B-Tree(多路平衡查找树)
    • 2.3 B+Tree
    • 2.4 Hash
  • 3. 索引分类
  • 4. 索引语法
  • 5. SQL性能分析
    • 5.1 SQL执行频率
    • 5.2 慢查询日志
    • 5.3 profile
    • 5.4 explain执行计划
      • 5.3.1 EXPLAIN执行计划各字段含义:
  • 6. 索引使用
    • 6.1 最左前缀法则
    • 6.2 范围查询
    • 6.3 索引列运算
    • 6.4 字符串不加引号
    • 6.5 模糊匹配
    • 6.6 or连接的条件
    • 6.7 数据分布影响
    • 6.8 SQL提示
    • 6.9 覆盖索引
    • 6.10 前缀索引
    • 6.11 单列索引与联合索引
  • 7. 索引设计原则

1. 索引概述

介绍

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

优缺点

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

2. 索引结构

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

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

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

2.1 二叉树

在这里插入图片描述

二叉树缺点:顺序插入时,会形成一个链表,查询性能大大降低。数据量大的情况下,层级较深,检索速度慢

红黑树:数据量大的情况下,层级较深,检索速度慢

2.2 B-Tree(多路平衡查找树)

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

在这里插入图片描述
Ps:树的度数指的是一个节点的子节点的个数

上图中有4个key,分别是20、30、62、89,其对应5个指针,小于20的对应第一个指针,20-30之间对应第二个指针,30-62之间对应第三个指针,62-89之间对应第四个指针,大于89的对应第五个指针

具体可参考B-Tree Visualization,在该网站中选择Max. Degree = 5,插入以下数据:

100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250

效果如下:

在这里插入图片描述

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

2.3 B+Tree

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

在这里插入图片描述
在B+ Tree Visualization中选择5阶,同样插入以上数据,效果如下:

在这里插入图片描述

相对于B-Tree区别:

① 所有的数据都会出现在叶子节点
② 叶子节点形成一个单向链表

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

在这里插入图片描述

2.4 Hash

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

• Hash索引特点

  1. Hash索引只能用于对等比较(=, in),不支持范围查询(between, >, <, …)
  2. 无法利用索引完成排序操作
  3. 查询效率高,通常只需要一次检索就行了,效率通常要高于B+Tree索引

• 存储引擎支持

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

3. 索引分类

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

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

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

聚集索引选取规则:

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

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;

• 案例演示

-- 创建表tb_user
create table tb_user(id int auto_increment primary key comment '主键ID',name varchar(10) comment '姓名',phone char(11) comment '手机号',email varchar(30) comment '邮箱',profession varchar(20) comment '专业',age int check ( age > 0 and age < 100 ) comment '年龄',gender int check ( gender = 1 or gender = 2 ) comment '性别',status char(1) comment '状态',createtime datetime comment '创建时间'
) comment '信息表';-- 添加数据
insert into tb_user(name, phone, email, profession, age, gender, status, createtime)
values('安景辉', 13080354567, 'anjinghui@example.com', '软件工程', 23, 1, 6, '2001-02-02 00:00:00'),('白佳颖', 13097742368, 'baijiaying@example.com', '通讯工程', 26, 2, 0, '2001-03-05 00:00:00'),('柏凡', 13123456789, 'bofan@example.com', '英语', 25, 1, 2, '2002-03-02 00:00:00'),('陈梦洁', 13245678901, 'chenmengjie@example.com', '工程造价', 27, 2, 0, '2001-07-02 00:00:00'),('曹宇涛', 13356789012, 'caoyutao@example.com', '软件工程', 22, 1, 1, '2001-04-22 00:00:00'),('董碧云', 13467890123, 'dongbiyun@example.com', '舞蹈', 22, 2, 0, '2001-02-07 00:00:00'),('单景瑞', 13578901234, 'shanjingrui@example.com', '应用数学', 27, 1, 0, '2001-02-08 00:00:00'),('冯彩云', 13689012345, 'fengcaiyun@example.com', '化工', 28, 2, 5, '2001-05-23 00:00:00'),('范石磊', 13790123456, 'fanshilei@example.com', '金属材料', 30, 1, 0, '2001-09-18-00:00:00'),('关海燕', 13801234567, 'guanhaiyan@example.com', '机械工程及其自动化', 27, 2, 2, '2001-08-16 00:00:00'),('高少杰', 13912345678, 'gaoshaojie@example.com', '无机非金属材料工程', 26, 1, 0, '2001-06-12 00:00:00'),('韩楚仪', 13112345678, 'hanchuyi@example.com', '会计', 23, 2, 0, '2001-05-11 00:00:00'),('郝飞羽', 13212345678, 'haofeiyu@example.com', '工程造价', 32, 1, 1, '2001-04-09 00:00:00'),('贺冰倩', 13312345678, 'hebingqian@example.com', '应用数学', 25, 2, 2, '2001-04-10 00:00:00'),('黄浩然', 13412345678, 'huanghaoran@example.com', '软件工程', 24, 1, 3, '2001-02-12 00:00:00'),('黄欣茹', 13512345678, 'huangxinru@example.com', '软件工程', 24, 2, 0, '2001-01-30 00:00:00'),('江逸舟', 13612345678, 'jiangyizhou@example.com', '工业经济', 35, 1, 0, '2000-05-03 00:00:00'),('李佳妮', 13712345678, 'lijiani@example.com', '化工', 38, 2, 1, '2001-08-08 00:00:00'),('康正乐', 13812345678, 'kangzhengle@example.com', '国际贸易', 30, 1, 0, '2007-03-12 00:00:00'),('刘可颐', 13987654321, 'liukeyi@example.com', '城市规划', 39, 2, 0, '2001-08-15 00:00:00'),('李海洋', 13012345678, 'lihaiyang@example.com', '城市规划', 40, 1, 0, '2000-04-12 00:00:00'),('马一鸣', 13187654321, 'mayiming@example.com', '土木工程', 21, 1, 3, '2002-07-18 00:00:00'),('林泽洋', 13287654321, 'linzeyang@example.com', '城市园林', 20, 1, 0, '2002-03-10 00:00:00'),('秦芷妍', 13387654321, 'qinzhiyan@example.com', '工程造价', 29, 2, 4, '2003-05-26 00:00:00');-- 查询索引
show index from tb_user;
-- 1.name字段为姓名字段,该字段的值可能会重复,为该字段创建索引
create index idx_user_name on tb_user(name);
-- 2. phone手机号字段的值是非空且唯一的,为该字段创建唯一索引
create unique index idx_user_phone on tb_user(phone);
-- 3. 为profession、age、status创建联合索引
create index idx_user_pro_age_sta on tb_user(profession, age, status);
-- 4. 为email建立合适的索引来提升查询效率
create index idx_user_email on tb_user(email);-- 删除索引
drop index idx_user_name on tb_user;
drop index idx_user_pro_age_sta on tb_user;
drop index idx_user_phone on tb_user;
drop index idx_user_email on tb_user;

查询结果如下:

在这里插入图片描述

5. SQL性能分析

5.1 SQL执行频率

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

SHOW GLOBAL STATUS LIKE ‘Com_______’;

其中,show session status是查看当前会话的状态信息,show global status是查看全局的状态信息,如下:

在这里插入图片描述

5.2 慢查询日志

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

SHOW VARIABLES LIKE ‘slow_query_log’;
在这里插入图片描述

而查询慢查询日志时间的指令如下:

SHOW VARIABLES LIKE ‘long_query_time’;
在这里插入图片描述

Linux(centOS)中需在MySQL的配置文件(etc/my.cnf)中配置如下信息以开启慢查询日志开关:

# 开启MySQL慢查询日志查询开关
slow_query_log=1
# 设置慢查询日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2

详细配置及操作如下:

① 首先输入以下指令对/etc/my.cnf进行编辑

vi /etc/my.cnf

② 按’i’键进行编辑,并在文档末尾添加如下语句:

# 开启慢查询日志开关
slow_query_log=1
# 设置慢查询日志时间为2秒
long_query_time=2

③ 按’Esc’键退出编辑,输入’:x’或’:wq’或’:wq!'保存并退出

④ 重启MySQL服务器

systemctl restart mysqld

⑤ 慢查询日志文件存路径:/var/lib/mysql/localhost-slow.log

在这里插入图片描述
如该位置没有该文件可在MySQL中通过命令show varaiables like ‘%slow_query_log_file%’查看慢查询日志存放位置

⑥ 查看localhost-slow.log内容

cat localhost-slow.log
在这里插入图片描述
从中可以看到,除了MySQL版本号、端口号等信息外并无其他多余信息

⑦ 查看慢查询日志文件尾部实时输出的内容的命令(单独新建个窗口以便查看实时输出)

tail -f localhost-slow.log
在这里插入图片描述

⑧ 在另一窗口执行MySQL指令,如查询tb_user表的数据:

select * from tb_user;
在这里插入图片描述

可以看到,由于查询时间未超过2秒,所以慢查询日志实时输出并没有出现数据。接下来使数据库睡眠3秒,再查看慢日志查询实时输出:

select sleep(3);
在这里插入图片描述

此时,睡眠的指令可以在慢查询日志中看到,而Windows端的慢查询日志开启请参考https://www.cnblogs.com/taozihua/p/10331897.html

5.3 profile

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

SELECT @@have_profiling;

profiling默认是关闭的,可以通过以下指令查看profiling是否开启:

SELECT @@profiling;
若为0,则为关闭状态,若为1,则为开启状态

若profiling处于关闭状态,可通过set语句开启profiling:

set [global | session] profiling=1

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

# 查看每一条SQL的耗时基本情况
show profiles;
# 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
# 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;

案例演示

-- 查询profiling是否打开
select @@profiling;-- 开启profiling
set profiling = 1;-- 执行SQL操作
select * from tb_user;
select * from tb_user where id = 15;
select * from tb_user where name = '单景瑞';
select count(*) from tb_user;
select * from tb_user where gender = 1;
select sleep(3);-- 查看每一条sql的耗时基本情况
show profiles;

此时,运行结果如下:
在这里插入图片描述

-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query 11;

此时,运行结果如下:
在这里插入图片描述

-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query 11;

在这里插入图片描述

5.4 explain执行计划

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

语法:

# 直接在select语句之前加上关键字explain / desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

演示

explain select * from tb_user where id = 8;

结果如下:
在这里插入图片描述

5.3.1 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的值越大越好

案例演示

案例中所演示的表分别为students、courses、student_course以及tb_user,在MySQL基础4-多表查询以及本文中可以找到对应的表

id

explain select s.* from students s where s.id in (select sc.student_id from student_course sc where sc.sourse_id = (select c.id from courses c where c.name = 'Python'));

运行结果如下:

在这里插入图片描述

从图中可以看到,SQL语句编写顺序是students、student_course、courses,但从执行结果来看,id最大的为3,

对应为courses表,这是最先执行的,其次是id为2的student_course表,然后id相同的则由上而下顺序执行,也就

是先执行<subquery 2>(第二个子查询),最后才执行students表的查询。

select_type

select_type参考意义不大,它只是说明当前SQL语句的查询类型

type

type代表访问的类型,如:

explain select * from tb_user where id = 1;

在这里插入图片描述

在该查询中,连接类型为const,而type访问类型中,性能由好至差分别为 NULL、system、const、eq_ref、ref、range、

index、all。其中 system 只有访问系统表的时候才会出现,根据主键、唯一索引进行访问,一般会出现const,如:

show index from tb_user;
select * from tb_user;
explain select * from tb_user where phone = '13689012345';

在这里插入图片描述

在这里插入图片描述

如果使用非唯一性的索引进行查询时,就会出现ref,如:

explain * from tb_user where name = '黄浩然';

在这里插入图片描述

在优化SQL语句的时候,尽量把type往前优化,尽量不要出现all,如果出现all的话,代表全表扫描,性能会比较低

如果出现index,代表用了索引,但也会对索引进行扫描,虽然比all快,但性能也比较低

extra代表额外的信息,也就是说,在执行查询的过程当中,在前面几个字段中没有展现出来的值,将会在extra进行展示

关于posssible_key、key、key_len、rows 在此不多做演示

重点关注:  type、possible_key、key、ken_len

6. 索引使用

6.1 最左前缀法则

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

案例演示

本案例中所用的表为本文中创建的tb_user表

explain select * from tb_user where profession = '软件工程' and age = 24 and status = '0';

运行结果如下:

在这里插入图片描述

该查询用到了联合索引,索引长度为93,profession、age、status这三个字段的索引全用上了,符合最左前缀法则,且中间并未跳过任何一列

explain select * from tb_user where profession = '软件工程' and age = 24;

运行结果如下:

在这里插入图片描述

该查询索引长度为88,意味着status字段的索引长度为5,该查询也满足最左前缀法则,中间并未跳过某一列

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

运行结果如下:

在这里插入图片描述

该查询语句只查询了profession字段,并未跳过某一列,所以也满足最左前缀法则,且可由前两条查询结果推断出age 的索引长度为5

select * from tb_user where profession = '软件工程' and status = '0';

运行结果如下:

在这里插入图片描述

该查询索引长度为83,意味着profession用到索引,而status没用到,所以索引长度和单独查询profession字段的索引长度是一样的。原因是profession和status间还有一个字段age被跳过,这导致了索引部分失效,也就是status字段的索引失效

explain select * from tb_user where age = 24 and status ='0';

运行结果如下:

在这里插入图片描述

该查询用到的是全表扫描而不是索引,因为最左边的profession字段并未存在,所以该查询不满足最左前缀法则,导致索引失效

explain select * from tb_user where age = 24 and status = '0' and profession = '软件工程';

运行结果如下:

在这里插入图片描述

该查询也用到了索引,因为最左前缀法则要求的是最左列必须存在,但并不意味着最左列的顺序必须是最左边,所以该查询语句满足最左前缀法则

总结: 最左前缀法则要求包含索引中最左边的列,如果最左边的列不存在,索引失效,如果跳过了其中某一列,该列后面的索引将会失效

6.2 范围查询

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

案例演示

explain select * from tb_user where profession = '软件工程' and age > 23 and status = '0';

运行结果如下:

在这里插入图片描述

结合前文来看,该查询满足最左前缀法则,但索引长度为88,说明age后面的那一列,也就是status索引失效。而在业务允许的情况下,尽量用 >= 或 <= 来代替,以规避索引失效的情况

explain select * from tb_user where profession = '软件工程' and age >= 23 and status = '0';

运行结果如下:

在这里插入图片描述

6.3 索引列运算

不要在索引列上进行运算操作,否则索引将失效

案例演示

-- 查询手机尾号为56的用户信息
select * from tb_user where substring(phone,10,2) = '56';-- 查看执行信息
explain select * from tb_user where substring(phone,10,2) = '56';

运行结果如下:

在这里插入图片描述

可以看到,在索引列phone上引用函数运算substring后,索引失效,所以在业务中应尽量减少对索引列进行运算的操作

6.4 字符串不加引号

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

案例演示

select * from tb_user where phone = 13912345678;explain select * from tb_user where phone = 13912345678;

运行结果如下:

在这里插入图片描述

在该查询语句中,由于phone字段作为字符串在查询的时候未加引号,导致索引失效

6.5 模糊匹配

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

案例演示

-- 尾部模糊匹配
select * from tb_user where profession like '软件%';explain select * from tb_user where profession like '软件%';-- 头部模糊匹配
select * from tb_user where profession like '%工程';explain select * from tb_user where profession like '%工程';

运行结果如下:

在这里插入图片描述

从中可以看到,在进行尾部模糊匹配时索引并未失效,但对头部进行模糊匹配时索引失效了

6.6 or连接的条件

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

案例演示

explain eslect * from tb_user where id = 15 or age = 24;explain select * from tb_user whre phone = '13412345678' or age = 24;

运行结果如下:

在这里插入图片描述

由于age字段没有索引,只有联合索引,而如果仅仅只对age字段进行查询,不满足最左前缀法则,联合索引不会用到。而正由于联合索引用不到,所以即使id、phone有索引,索引也会失效,所以需要针对age字段也建立索引

-- 建立age字段索引
create index idx_user_age on tb_user(age);-- 再次查询
explain select * from tb_user where id = 15 or age = 24;explain select * from tb_user where phone = '13412345678' or age = 24;

运行结果如下:

在这里插入图片描述

此时可以看到,在建立age字段的索引后,用到的是phone字段及age字段的索引,而非联合索引,所以该查询索引未失效

6.7 数据分布影响

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

** 案例演示**

explain select * from tb_user where phone >= '13612345678';explain select * from tb_user where phone >= '13112345678';explain select * from tb_user where phone >= '13012345678';

运行结果如下:
在这里插入图片描述

从中可以看到,在查询phone >= '13612345678’时用到了索引,这是因为MySQL在查询时评估该表中大部分phone值都小于该值,用索引查询比全表扫描快。但将phone改为’13112345678’或‘13012345678’时,MySQL评估全表大部分phone值都比这俩值大,用全表扫描会比用索引快,所以才进行全表扫描,同理还有:

explain select * from tb_user where profession is null;explain select * from tb_user where profession is not null;

在该查询中,由于tb_user表中的profession字段没有null值,所以第一个查询语句用到的是索引,而第二个查询语句用到的则是全表扫描,因为MySQL评估当查询时需要比较大部分值时,会优先使用全表扫描,而如果只是一小部分的话,则优先使用索引。当将profession字段的值都设置为null后,结果将相反,这里不做演示

6.8 SQL提示

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

在查询时,如果一个字段有多个索引,MySQL查询优化器会自动选择索引,如下:

-- 创建tb_user表中profession字段的索引
create index idx_user_pro on tb_user(profession);-- 查询
explain select * from tb_user where profession = '软件工程';

运行结果如下:

在这里插入图片描述

可以看到,在该查询中可能用到的索引分别为’idx_user_pro_age_sta’及’idx_user_pro’,而实际用到的索引为’idx_user_pro_age_sta’,这就是MySQL查询优化器自动选择的结果,如果想指定查询索引,可参考以下三条查询语句:

use  index(告诉数据库用哪个索引):

explain select * from tb_user use index(idx_user_pro) where profession = ‘软件工程’;

在这里插入图片描述

该查询语句只是给MySQL建议用指定查询,至于查询结果,取决于MySQL比较所指定的索引效率快不快后所给出的

ignore index(告诉数据库不用哪个索引):

explain select * from tb_user ignore index(idx_user_pro) where profession = ‘软件工程’;

在这里插入图片描述

force index(告诉数据库必须走哪个索引):

explain select * from tb_user force index(idx_user_pro) where profession = ‘软件工程’;

在这里插入图片描述

6.9 覆盖索引

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

案例演示

-- 删除多余索引,以减少干扰
drop index idx_user_age on tb_user;drop index idx_user_email on tb_user;drop index idx_user_pro on tb_user;-- 测试
explain select id, profession from tb_user where profession = '软件工程' and age = 24 and status = '0';explain select id, profession, age from tb_user where profession = '软件工程' and age = 24 and status = '0';explain select id, profession, age, status from tb_user where profession = '软件工程' and age = 24 and status = '0';explain select id, profession, age, status, name from tb_user where profession = '软件工程' and age = 24 and status = '0';explain select * from tb_user where profession = '软件工程' and age = 24 and status = '0';

运行结果如下:

在这里插入图片描述

从中可以看到Extra中的信息出现不同的地方,而其中’Using where; Using index’的语句的性能要高于’Using index contition’,还需注意的是,如果使用的MySQL版本不同Extra中出现的值,其展示的形式也是不同的

Ps:

using index condition:查找使用了索引,但是需要回表查询数据
using where; using index:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

6.10 前缀索引

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

创建前缀索引的语法

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

前缀长度

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

选择性计算演示

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

运行结果如下:

在这里插入图片描述

创建前缀索引演示

create index idx_email_5 on tb_user(email(5));show index from tb_user;

运行结果如下:
在这里插入图片描述

6.11 单列索引与联合索引

单列索引:即一个索引只包含单个列
联合索引:即一个索引包含了多个列

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

单列索引情况

explain select id, phone, name from tb_user where phone = '13012345678' and name = '李海洋';

在这里插入图片描述

多条件联合查询时,MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询

联合索引情况

-- 创建联合索引
create unique index idx_user_phone_name on tb_user(phone, name);explain select id, phone, name from tb_user where phone = '13012345678' and name = '李海洋';-- 强制使用联合索引
explain select id, phone, name from tb_user force index(idx_user_phone_name) where phone = '13012345678' and name = '李海洋';

运行结果如下:
在这里插入图片描述

7. 索引设计原则

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

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

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot+FastJson 优雅的过滤 Response Body

Spring 源码系列 1、Spring 学习之扩展点总结之后置处理器&#xff08;一&#xff09; 2、Spring 学习之扩展点总结之后置处理器&#xff08;二&#xff09; 3、Spring 学习之扩展点总结之自定义事件&#xff08;三&#xff09; 4、Spring 学习之扩展点总结之内置事件&#xf…

手把手教你Linux查找Java的安装目录并设置环境变量以及Linux下执行javac未找到命令的保姆级教学

查找Java的安装目录 输入 java -version&#xff0c;查看是否成功安装Java 输入 which java&#xff0c;查看Java的执行路径 输入 ls -lrt /usr/bin/java 输入 ls -lrt /etc/alternatives/java&#xff0c;/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7.x86_64 就是J…

自动化测试(终章)webdriver的常用api(2)以及新的开始

目录 多层框架/窗口定位 多层框架的定位 frame是什么&#xff1f; 多层窗口定位 层级定位 使用 XPath 进行层级定位&#xff1a; 使用 CSS 选择器进行层级定位&#xff1a; 下拉框处理 alert、confirm、prompt 的处理 Alert 弹窗&#xff1a; Confirm 弹窗&#xff…

IDEA安装插件搜索不到插件的解决方法

解决idea安装所需插件&#xff0c;插件搜索不到的问题 1.通过设置代理和去掉使用安装链接的方式来解决的 File–>Settings–>Appearance & Behavior–>System Settings—>HTTP Proxy(修改为图片所示) 2.在系统设置中将更新选项中的“use secure connection”…

Xml与Json格式在线转换器

具体请前往&#xff1a;在线Json转Form表单参数工具

C语言之函数式宏

目录 函数和数据类型 函数式宏 函数和函数式宏 函数式宏和对象式宏 不带参数的函数式宏 函数式宏和逗号运算符 函数式宏和函数类似并且比函数更加灵活&#xff0c;下面我们就来学习函数式宏的相关内容。 函数和数据类型 我们来编写一个程序&#xff0c;它能计算出所读取…

Jetpack Compose开发一个Android WiFi导航应用

在以前的一篇文章构建一个WIFI室内定位系统_wifi定位系统-CSDN博客中&#xff0c;我介绍了如何用Android来测量WiFi信号&#xff0c;上传到服务器进行分析后&#xff0c;生成室内不同地方的WiFi指纹&#xff0c;从而帮助进行室内导航。当时我是用的HTML5的技术来快速开发一个An…

QQ邮箱发送工具类的实现

我们在日常开发中&#xff0c;需要实现一个对邮箱的发送&#xff0c;今天就实现邮箱的发送工具类&#xff0c;只需要一些注册邮箱之后的配置即可&#xff0c;我这边使用的是qq邮箱 0.加上依赖 <!--邮箱--><dependency><groupId>org.springframework.boot&l…

基于vue开发 - 编写登录页面样式

vue创建项目&#xff0c;使用可视化界面安装插件-CSDN博客 使用vue UI安装路由插件-CSDN博客 基于vue开发-创建登录页-CSDN博客 在src/views文件夹中创建登录页面login.vue&#xff0c;在router/index.js文件中加入登录页的路由&#xff0c;然后在浏览器中输入登录页的路径就…

FL Studio终身永久2024中文版下载安装详细操作图文步骤教程

FL Studio2024版是一款在国内非常受欢迎的多功能音频处理软件&#xff0c;我们可以通过这款软件来对多种不同格式的音频文件来进行编辑处理。而且FL Studio 2024版还为用户们准备了超多的音乐乐器伴奏&#xff0c;我们可以直接一键调取自己需要的音调。 FL Studio 2024版不仅拥…

算法设计基础——综合

算法设计基础中最基础的几种算法&#xff1a;分治法、减治法、贪心法、动态规划法、回溯法基本都掌握后&#xff0c;我们现在可以对这些算法做整体的比较&#xff0c;本次实验使用蛮力法、动态规划法、回溯法来求解0/1背包问题&#xff0c;来比较各个算法的优劣。 1. 蛮力法 …

代码随想录27期|Python|Day16|二叉树|104.二叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数

二叉树专题&#xff0c;重点掌握后续的递归和中间节点的处理。 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 本题在前一章已经解决了层序遍历的解法&#xff0c;现在来聊一下递归法。 首先需要明确两个概念&#xff1a;深度和高度。&#xff08;注意&…

抠图软件哪个好用?什么软件可以抠图换背景?

抠图软件哪个好用&#xff1f;在图片处理中&#xff0c;抠图换背景是一项常见的操作。很多新手可能会对此感到困惑&#xff0c;不知道应该使用什么软件来进行抠图换景。实际上&#xff0c;现在市面上有很多图片处理软件都具备抠图换背景的功能&#xff0c;每款软件都有其优缺点…

LVS负载均衡群集部署 DR模式

目录 DR模式直接路由 LVS-DR工作原理 LVS-DR 数据包流向分析 DR 模式的特点 DR模式 LVS负载均衡群集部署 DR模式直接路由 Direct Routing&#xff0c;简称DR模式&#xff0c;采用半开放式的网络结构&#xff0c;与TUN模式的结构类似&#xff0c;但各节点并不是分散在各地…

c语言链表的基本操作

在C语言中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表的基本操作包括创建、插入、删除和遍历等。 下面是一个简单的链表节点结构体定义&#xff1a; struct Node { int da…

Python实现员工管理系统(Django页面版 ) 六

本篇博客主要实现用户账号管理&#xff0c;这与之前的账号管理不同&#xff0c;之前的账号管理你可以理解为公司在外面买的一些手机号然后需要发放给员工做内部使用&#xff0c;而本篇博客的用户账号管理主要是为了后续的登录网页实现&#xff0c;那么我们开始今天的项目实现吧…

2. 套圈(分治)

题目 Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded. In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it c…

搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 搭建消息时光机&#xff1a;深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用 引言前言第一&#xff1a;开启插件支持第二&#xff1a;springboot整合第三&#xff1a;效果展示交换机属…

locust 压测 websocket

* 安装 python 3.8 https://www.python.org/ py --version * 安装 locust pip install locust2.5.1 -i http://pypi.douban.com/simple/ pip install locust2.5.1 -i https://pypi.mirrors.ustc.edu.cn/simple/ locust -V 备注&#xff1a;-i 是切换下载源 * 安装依赖 pip ins…

Electron框架:构建跨平台桌面应用的终极解决方案

文章目录 一、Electron框架简介二、Electron框架的优势1. 开发效率高2. 跨平台性能好3. 易于维护4. 强大的原生能力 三、如何使用Electron框架快速开发跨平台桌面应用1. 安装Electron2. 创建项目文件夹3. 编写主进程代码4. 编写界面代码5. 运行应用 《Electron入门与实战》编辑…