MySQL索引优化(一)

news2024/11/25 15:48:05

文章目录

  • 一、索引介绍
    • 1. 什么是MySQL的索引
    • 2. 索引数据结构
    • 3. 索引优势
    • 4. 索引劣势
    • 5. 索引使用场景
      • (1)需要建立索引的场景
      • (2)不推荐建立索引的场景
    • 6. 索引分类
      • (1)主键索引
      • (2)唯一索引
      • (3)单值索引
      • (4)复合索引
    • 7. 创建索引实操
    • 8. 索引测试
  • 二、性能分析(基于mysql 5.7演示)
    • 1. MySQL常见瓶颈
    • 2. Explain
    • 3. Explain之id
      • (1)id相同
      • (2)id不同
      • (3)id相同和id不同都存在
    • 4. Explain之select_type
      • (1)simple
      • (2)primary
      • (3)derived
      • (4)subquery
      • (5)union
    • 5. Explain之table
    • 6. Explain之type
      • (1)System
      • (2)Const
      • (3)eq_ref
      • (4)Ref
      • (5)Range
      • (6)Index
      • (7)All
    • 7. Explain之possible_keys
    • 8. Explain之key
    • 9. Explain之ref
    • 10. Explain之rows
    • 11. Explain之extra
      • (1)using filesort
      • (2)using temporary
      • (3)Using index
      • (4)Using where

一、索引介绍

1. 什么是MySQL的索引

MySQL官方对于索引的定义:索引是帮助MySQL高效获取数据的数据结构。

MySQL在存储数据之外,数据库系统中还维护着满足特定查找算法的数据结构,这些数据结构以某种引用(指向)表中的数据,这样我们就可以通过数据结构上实现的高级查找算法来快速找到我们想要的数据。而这种数据结构就是索引
简单理解为“排好序的可以快速查找数据的数据结构”。

2. 索引数据结构

下图就是一种可能的二叉树的索引方式:
在这里插入图片描述
二叉树数据结构的弊端:当极端情况下,数据递增插入时,会一直向右插入,形成链表,查询效率会降低。

MySQL中常用的的索引数据结构有BTree索引(Myisam普通索引),B+Tree索引(Innodb普通索引),Hash索引(memory存储引擎)等等。

3. 索引优势

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

4. 索引劣势

索引实际上也是一张表,保存了主键和索引的字段,并且指向实体表的记录,所以索引也是需要占用空间的。
在索引大大提高查询速度的同时,却会降低表的更新速度,在对表进行数据增删改的同时,MySQL不仅要更新数据,还需要保存一下索引文件。

5. 索引使用场景

(1)需要建立索引的场景

1.主键自动建立唯一索引
2.频繁作为查询条件的字段应该创建索引(where 后面的语句)
3.查询中与其它表关联的字段,外键关系建立索引
4.多字段查询下倾向创建组合索引
5.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
6.查询中统计或者分组字段

(2)不推荐建立索引的场景

1.表记录太少
2.经常增删改的表
3.Where条件里用不到的字段不建立索引

6. 索引分类

(1)主键索引

1.表中的列设定为主键后,数据库会自动建立主键索引。
2.单独创建和删除主键索引语法:
创建主键索引语法: alter table 表名 add primary key (字段);
删除主键索引语法: alter table 表名 drop primary key;

(2)唯一索引

1.表中的列创建了唯一约束时,数据库会自动建立唯一索引。
2.单独创建和删除唯一索引语法:
创建唯一索引语法:alter table 表名 add unique 索引名(字段); 或 create unique index 索引名 on 表名(字段);
删除唯一索引语法:drop index 索引名 on 表名;

(3)单值索引

即一个索引只包含单个列,一个表可以有多个单值索引。
1.建表时可随表一起建立单值索引
2.单独创建和删除单值索引:
创建单值索引: alter table 表名 add index 索引名(字段); 或 create index 索引名 on 表名(字段);
删除单值索引:drop index 索引名 on 表名;

(4)复合索引

即一个索引包含多个列
1.建表时可随表一起建立复合索引
2.单独创建和删除复合索引:
创建复合索引:create index 索引名 on 表名(字段1,字段2); 或 alter table 表名 add index 索引名(字段,字段2);
删除复合索引:drop index 索引名 on 表名;

7. 创建索引实操

上面介绍的是创建完表后,单独创建索引的语法。
下面是创建表的同时建立索引。

#随表建立索引
create table customer(
	id int(10) auto_increment,
	customer_no varchar(20),
	customer_name varchar(20),
	primary key(id) ,
	unique idx_customer_no(customer_no),
	key idx_customer_name(customer_name),
	key idex_customer_no_name(customer_no,customer_name)
);

在这里插入图片描述

在这里插入图片描述

8. 索引测试

1.通过存储过程往数据库中插入300W条数据。
2.分别测试使用索引和没有使用索引的情况下,where查询的一个效率对比。

  • 创建表
-- 建表
DROP TABLE IF EXISTS person;
CREATE TABLE person  (
  PID int(11) AUTO_INCREMENT COMMENT '编号',
  PNAME varchar(50) COMMENT '姓名',
  PSEX varchar(10) COMMENT '性别',
	PAGE	int(11) COMMENT '年龄',
  SAL decimal(7, 2) COMMENT '工资',
  PRIMARY KEY (PID)
);
-- 创建存储过程
create procedure insert_person(in max_num int(10))
begin
	declare i int default 0;
	set autocommit = 0; 
	repeat
	set i = i +1;
	insert into person (PID,PNAME,PSEX,PAGE,SAL) values (i,concat('test',floor(rand()*10000000)),IF(RAND()>0.5,'男','女'),FLOOR((RAND()*100)+10),FLOOR((RAND()*19000)+1000));
	until i = max_num
	end repeat;
	commit;
end;

-- 调用存储过程
call insert_person(3000000);
-- 不使用索引,根据pName进行查询
select * from person where PNAME = "test1209325"; #查询时间1.167S

-- 给PNAME建立索引
alter table person add index idx_pname(PNAME);
select * from person where PNAME = "test1209325"; #查询时间0.024S

二、性能分析(基于mysql 5.7演示)

1. MySQL常见瓶颈

SQL中对大量数据进行比较、关联、排序、分组时CPU的瓶颈。
实例内存满足不了缓存数据或排序等需要,导致产生大量的物理IO。查询数据时扫描过多数据行,导致查询效率低。

2. Explain

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MYSQL是如何处理SQL语句的。
可以用来分析查询语句或者表结构的性能瓶颈。
其作用:
(1)表的读取顺序
(2)哪些索引可以使用
(3)数据读取操作的操作类型
(4)哪些索引被实际使用
(5)表之间的引用
(6)每张表有多少行被优化器查询

XPLAIN关键字使用起来比较简单: explain + SQL语句。
在这里插入图片描述

  • 创建表
--  创建四张测试表
CREATE TABLE t1(
	id INT(10) AUTO_INCREMENT,
	content  VARCHAR(100),  
	PRIMARY KEY (id)
);
CREATE TABLE t2(
	id INT(10) AUTO_INCREMENT,
	content  VARCHAR(100),
	PRIMARY KEY (id)
);
CREATE TABLE t3(
	id INT(10) AUTO_INCREMENT,
	content  VARCHAR(100),
	PRIMARY KEY (id)
	);
CREATE TABLE t4(
	id INT(10) AUTO_INCREMENT,
	content  VARCHAR(100),
	PRIMARY KEY (id)
);

-- 每张表中添加一条数据
INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000)));

INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));

INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));
	
INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. Explain之id

select查询的序列号,表示查询中执行select子句或操作表的顺序。
id 列的编号是 select 的序列号,一般有几个 select 就有几个 id(联表查询会有重复的 id),并且 id 的顺序是按 select 出现的顺序增长的。
id相同时(一般出现在联表查询),执行顺序由上至下。
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,则先被执行。
id相同和不同都存在时,id相同的可以理解为一组,从上往下顺序执行,所有组中,id值越大,优先级越高越先执行。
id 为 NULL 最后执行。

(1)id相同

#id相同时,执行顺序是从上往下。
explain select * from t1,t2,t3 where t1.id=t2.id and t2.id = t3.id;

在这里插入图片描述

(2)id不同

#id不同时,如果是子查询,id的序号会递增,id值越大优先级越高,则先被执行。
explain select t1.id from t1 where 
t1.id in ((select t2.id from t2), (select t3.id from t3));

在这里插入图片描述

(3)id相同和id不同都存在

#id相同和不同都存在时,id相同的可以理解为一组,从上往下顺序执行,所有组中,id值越大,优先级越高越先执行。
explain select t2.* from t2, (select * from t3) s3 where s3.id = t2.id;

在这里插入图片描述

4. Explain之select_type

查询的类型,常见值有:
SIMPLE :简单的 select 查询,查询中不包含子查询或者UNION。
PRIMARY:查询中若包含任何复杂的子查询,最外层查询则被标记为Primary。
DERIVED:在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表里。
SUBQUERY: 在SELECT或WHERE列表中包含了子查询。
UNION:在 UNION中的第二个或之后的 select。

(1)simple

#simple 简单的select查询
explain select * from t1;

在这里插入图片描述

(2)primary

#primary
explain select * from (select 1) s1;

在这里插入图片描述

(3)derived

【注】在 MySQL 5.7 中,会对衍生表进行合并优化,如果要直观的查看 select_type 的值,需要临时关闭该功能(默认是打开的),下面的介绍中凡是涉及到衍生表的都需要该操作。

# 关闭衍生表的合并优化(只对该会话有效)
set session optimizer_switch='derived_merge=off'; 
# 打开衍生表的合并优化(只对该会话有效)
set session optimizer_switch='derived_merge=on';
#derived  
explain select * from (select t1.content from t1) s1;

在这里插入图片描述

“< derived2>”,这个“derived”表示衍生的意思,而其中的“2”表示id=2的这一行。

(4)subquery

#subquery
explain select t2.* from t2 where t2.id = (select t3.id from t3);

在这里插入图片描述

(5)union

EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2;

在这里插入图片描述

5. Explain之table

显示这一行的数据是关于哪张表的。

6. Explain之type

访问类型排序:
在这里插入图片描述
从最好到最差依次是:system>const>eq_ref>ref>range>index>All 。一般来说,最好保证查询能达到range级别,最好能达到ref。

(1)System

System:表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计。

#system
explain select * from (select t1.id from t1 where id = 1) t;

在这里插入图片描述

(2)Const

表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快,如将主键置于where列表中,MySQL就能将该查询转换为一个常量。

#const 索引一次就找到了
explain select * from t1 where id = 1;

在这里插入图片描述

(3)eq_ref

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。

#eq_ref
explain select t1.*,t2.* 
from t1
join t2
on t1.id = t2.id;

在这里插入图片描述

(4)Ref

Ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。

#ref非唯一索引扫描
alter table t1 add index idx_t1_content(content);
explain select * from t1 where t1.content = "abc";

在这里插入图片描述

(5)Range

Range:只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引
一般就是where语句中出现了between、<、>、in等的查询,这种范围扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。

#range
explain select * from t2 where t2.id > 0;

在这里插入图片描述

(6)Index

Index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的。

#index
explain select id,content from t1;

在这里插入图片描述

(7)All

All:Full Table Scan,将遍历全表以找到匹配的行。

#All
explain select * from t1 where t1.content = "abc";

在这里插入图片描述

7. Explain之possible_keys

显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上如果存在索引,则该索引将会被列出来,但不一定会被查询实际使用上。

explain select * from t2 where t2.id is not null;
  • 索引失效,但possible_keys依然有值
    在这里插入图片描述

8. Explain之key

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

explain select * from t2 where t2.id = 1;

在这里插入图片描述

9. Explain之ref

显示索引的哪一列被使用了。哪些列或常量被用于查找索引列上的值。

explain select t2.*,t3.* from t2,t3 where t2.id = t3.id;
  • t3表,引用了t2表的id列,作为索引列进行查找
  • 在这里插入图片描述

10. Explain之rows

rows列显示MySQL认为它执行查询时必须检查的行数。一般越少越好。

#删除person上的索引
drop index idx_pname on person;
explain select person.* from person where pname = "test3263609";

在这里插入图片描述

#添加索引
alter table person add index idx_pname(PNAME);
explain select person.* from person where pname = "test3263609";

在这里插入图片描述

11. Explain之extra

一些常见的重要的额外信息:
Using filesort:MySQL无法利用索引完成的排序操作称为“文件排序”,效率低。
Using temporary:Mysql在对查询结果排序时使用临时表,常见于排序order by和分组查询group by。
Using index:表示索引被用来执行索引键值的查找,避免访问了表的数据行,效率不错。
Using where:表示使用了where过滤。

  • 创建表
drop table if exists emps;
CREATE TABLE emps (
  id INT PRIMARY KEY AUTO_INCREMENT COMMENT "主键id",
  name VARCHAR (24) COMMENT '姓名',
  age INT COMMENT '年龄',
  job VARCHAR (20) COMMENT '职位'
);
 
INSERT INTO emps(name,age,job) VALUES('zhangsan',22,'manager');
INSERT INTO emps(name,age,job) VALUES('lisi',23,'clerk');
INSERT INTO emps(name,age,job) VALUES('wangwu',24,'salsman');
INSERT INTO emps(name,age,job) VALUES('赵六',23,'salsman');

(1)using filesort

-- using filesort 排序时没有使用索引
explain select * from emps order by age;

在这里插入图片描述

(2)using temporary

-- using temporary 分组时没有使用索引,分组时会进行排序,所以一般Using temporary; Using filesort会同时出现
explain select count(*),job from emps group by job;

在这里插入图片描述

(3)Using index

-- using index 
explain select id from emps;

在这里插入图片描述

(4)Using where

-- using where
explain select * from emps where name = "张三";

在这里插入图片描述

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

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

相关文章

【k8s 实战】Prometheus Operator 高级配置- 监控Kubernetes自动发现

上文我们一起学习了如何在 Prometheus Operator 下面自定义一个监控选项&#xff0c;以及自定义报警规则的使用。那么我们还能够直接使用前面课程中的自动发现功能吗&#xff1f;如果在我们的 Kubernetes 集群中有了很多的 Service/Pod&#xff0c;那么我们都需要一个一个的去建…

MATLAB傅里叶变换和加入噪声后的傅里叶变换

1.傅里叶变换代码 查看String为傅里叶变换的button添加callback函数&#xff0c;可以通过查看callback函数快速定位到该位置 function pushbutton37_Callback(hObject, eventdata, handles)%傅里叶变换&#xff08;频谱图&#xff09; axes(handles.show_proImg); global fpat…

[附源码]Nodejs计算机毕业设计基于的二手房交易系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

动态规划——状态机模型

文章目录概述大盗阿福思路代码股票买卖 IV思路代码股票买卖 V思路代码总结概述 定义&#xff1a; 它是一个有向图形&#xff0c;由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内&#xff0c;其…

QT 6开发环境搭建——Windows环境

QT 目前不支持离线安装&#xff0c;只支持在线安装。&#xff08;从Qt5.15版本后不支持离线安装&#xff09; 去下面的网址&#xff0c;下载在线安装包&#xff1a; https://download.qt.io/archive/online_installers 我个人选择的是4.3.可以选择更新的版本。选择合适自己电…

时间序列的蒙特卡罗交叉验证

交叉验证应用于时间序列需要注意是要防止泄漏和获得可靠的性能估计本文将介绍蒙特卡洛交叉验证。这是一种流行的TimeSeriesSplits方法的替代方法。 时间序列交叉验证 TimeSeriesSplit通常是时间序列数据进行交叉验证的首选方法。下图1说明了该方法的操作方式。可用的时间序列…

编译原理实验三:算符优先分析算法的设计与实现(python)

实验目的 根据算符优先分析法&#xff0c;对表达式进行语法分析&#xff0c;使其能够判断一个表达式是否正确。通过算符优先分析方法的实现&#xff0c;加深对自下而上语法分析方法的理解。 实验内容 1、输入文法。可以是如下算术表达式的文法&#xff08;你可以根据需要适当…

赋能组织执行力学习-R4管理-结果体系、责任体系、检查与改进体系、及时激励体系

本文向大家介绍R4管理&#xff0c;是由结果体系&#xff08;Result&#xff09;、责任体系&#xff08;Responsibility&#xff09;、检查与改进体系&#xff08;Review&#xff09;、及时激励体系&#xff08;Reward&#xff09;组成&#xff0c;帮助我们如何更好的运用。 马云…

TikTok选品技巧 | 爆品一般是怎么选出来的,快看这些技巧

TikTok电商商家看过来&#xff01;随着短视频时代的兴起与发展&#xff0c;TikTok在全球受到越来越多的用户所追捧。同时&#xff0c;吸引了更多TikTok商家前来发展电商。但是&#xff0c;想要在这里快速实现TikTok变现目标&#xff0c;并非容易。TikTok选品和TikTok营销是最不…

数据库原理及MySQL应用 | 多表查询

在实际应用中&#xff0c;多表查询应用相对较多&#xff0c;根据多表之间的相关列&#xff0c;可以从多个表中检索出所需数据。 在实际应用中&#xff0c;单表查询应用范围相对较少&#xff0c;因为用户需要的数据往往存储在多个不同的表中&#xff0c;这时需要进行多表查询。…

oracle的pkg改为hivesql

1. oracle的() 改为hive左右连接 oracle ()学习_cclovezbf的博客-CSDN博客最近工作需要将oracle的存储过程转化为hive的sql脚本。遇到很多不一样的地方&#xff0c;例如oracle连接中有()号的用法。借鉴这篇文章&#xff0c;但是这个排版比较烂。。。先建表和插入数据首先说明…

笔试强训(四十六)

目录一、选择题二、编程题2.1 简单错误记录2.1.1 题目2.1.2 题解一、选择题 &#xff08;1&#xff09;一台刚接入互联网的WEB服务器第一次被访问到时&#xff0c;不同协议的发生顺序是下面中的&#xff08;A&#xff09; A.ARP->DNS->HTTP B.ARP->HTTP->DNS C.DN…

怎么提取伴奏?有什么实用的提取软件?

由于我喜欢唱歌&#xff0c;所以在读书时期偶尔会参加学校的一些歌唱比赛或是文艺汇演。而一开始的我没什么经验&#xff0c;练习时都是放着原声带跟唱&#xff0c;但是到了舞台上发现只有伴奏&#xff0c;一时间卡不到开唱的点&#xff0c;甚是尴尬。所以后来我吸取了教训&…

蓝桥杯嵌入式 cubeMX生成代码解读

文章目录前言一、代码风格二、为什么要这些注释&#xff1f;三、生成的独立模块的代码总结前言 本篇文章讲介绍一下cubeMX生成代码的风格。 一、代码风格 在main.c中可以看到非常多的注释代码&#xff0c;很多人都不知道这些是用来干嘛的&#xff0c;现在就给大家介绍一下这…

你了解Java中的ForkJoin吗?

什么是ForkJoin? ForkJoin 从字面上看Fork是分岔的意思&#xff0c;Join是结合的意思&#xff0c;我们可以理解为将大任务拆分成小任务进行计算求解&#xff0c;最后将小任务的结果进行结合求出大任务的解&#xff0c;这些裂变出来的小任务&#xff0c;我们就可以交给不同的线…

新智慧杂志新智慧杂志社新智慧编辑部2022年第30期目录

杏坛潮_热点关注 特色劳动教育模式探究——基于“劳动周”项目的设计与实践 王胜; 1-3《新智慧》投稿&#xff1a;cn7kantougao163.com “双减”背景下小学数学大单元深度学习的实践与探索——以小学高年级为例 王晓雪; 4-6 杏坛潮_创新教育 问题教学法在高中物理教…

20221215英语学习

今日新词&#xff1a; rich adj.富有的, 富裕的, 油腻的 luck n.运气, 幸运, 好运, 侥幸 live adj.活的, 现场直播的, 实况转播的, 现场演出的 tutor n.家庭教师&#xff1b;私人教师&#xff1b;导师&#xff1b;助教 swipe v.挥拳打, 扬起巴掌打, 挥起&#xff08;物体&…

刷屏的AI 绘画,你成功驯服了吗?其背后的AIGC模型你可能还不知道

文章目录前言基于 CLIP Latents 的条件文本图像生成BLIPHugging Face奇点智源中文-CLIP百度昆仑万维之AI绘画前言 随着人工智能技术的发展与完善&#xff0c;AIGC&#xff08;AI generated content&#xff09;在内容的创作上为人们的工作和生活带来前所未有的帮助&#xff0c…

SpringCloud(7)— ElasticSearch基础

SpringCloud&#xff08;7&#xff09;— Elasticsearch基础 一 初识Elasticsearch elasticserach是一个强大的开源搜索引擎&#xff0c;可以从海量数据中迅速找到想要的内容。 elasticsearch结合了 Kibana, Logstach, Beats,也就是 elastic stack。主要应用于日志数据分析&…

【信管4.1】范围与需求

范围与需求范围其实说白了就是我们要做的东西都包括哪些内容&#xff0c;这些内容的边界在哪里&#xff0c;范围其实从另一个角度来说的话&#xff0c;也可以看成是一个产品的约束。为什么要有一个约束呢&#xff1f;你见过一个即是电商&#xff0c;又是社交&#xff0c;还能兼…