Explain和索引基本优化示例

news2024/7/5 0:18:09

一、Explain介绍

1、Explain不用版本的使用

在mysql8.0版本只能用explain,已经弃用了explain extended和explain partitions,用了都会出现语法问题,只能用explain;在explain语句后面加上show warnings;可以查看mysql优化后的语句,但这些语句不一定能正确执行

  • explain extended

        在mysql8.0版本之前,explain extended语句后面加上show warning;可以查看mysql优化后的语句,row*filtered/100可以估算出表连接数

  • explain partitions

        查看表的分区信息

2、Explain查询的列

用三个这样的表更加好理解explain查询列的详细信息:

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(11) NOT NULL,
  `name` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `student` VALUES (1, 'a', '2023-06-15 09:22:45');
INSERT INTO `student` VALUES (2, 'b', '2023-06-15 09:22:45');
INSERT INTO `student` VALUES (3, 'c', '2023-06-15 09:22:45');
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `teacher` VALUES (3, 'teacher0');
INSERT INTO `teacher` VALUES (1, 'teacher1');
INSERT INTO `teacher` VALUES (2, 'teacher2');
DROP TABLE IF EXISTS `teacher_student`;
CREATE TABLE `teacher_student`  (
  `id` int(11) NOT NULL,
  `teacher_id` int(11) NOT NULL,
  `student_id` int(11) NOT NULL,
  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_teacher_student_id`(`teacher_id`, `student_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `teacher_student` VALUES (1, 1, 1, NULL);
INSERT INTO `teacher_student` VALUES (2, 1, 2, NULL);
INSERT INTO `teacher_student` VALUES (3, 2, 1, NULL);

     show warnings;查看mysql优化过后的sql

explain extended select * from teacher where id = 1;
show warnings;

查询的列:

  • id:查询出来的执行编号,编号越大越先执行,如果编号相等则由上到下依次执行,id为 null最后执行
  • select_type:
simple简单查询,基本上就一个select
primary复杂查询中最外层的select
subquery子查询,在select之后from之前的查询
derived衍生查询,在from之后的查询,把查询结果放到一个临时表中
union有用union或者union all连接两个查询
explain select * from teacher where id = 2;#simple查询
set session optimizer_switch='derived_merge=off'; #关闭mysql5.7新特性对衍生表的合并优化
explain select (select 1 from student where id = 1) from (select * from teacher where id = 1) der;
set session optimizer_switch='derived_merge=on'; #还原默认配置

 id值按照从大到小执行,首先看select_type为DERIVED(衍生查询,查询的表是teacher,from之后的查询);select_type为SUBQUERY(子查询,查询的表是student,select之后from之前的查询);select_type为PRIMARY(复杂查询,说明查询中包含其它查询,最外层的select)

explain select 1 union all select 1;#union类型查询
  • table:查询用到的表,如果查询需要依赖其它查询的结果,会包含其它explain查询id的值
  • partitions:分区信息
  • type:查询类型,查询速度由快到慢依次是system、const、eq_ref、ref、range、index、ALL,通常情况下最低保持在range级别

NULL:查询时不需要访问表

explain select 1;
explain select min(id) from student;

system:系统查询表时只有一条数据匹配

set session optimizer_switch='derived_merge=off'; #关闭mysql5.7新特性对衍生表的合并优化
explain select * from (select * from student where id = 1) test;
set session optimizer_switch='derived_merge=on'; #还原默认配置

 const:当查询只有一条数据与之匹配

explain select * from student where id = 1;

 eq_ref:当用主键或者唯一索引与主表进行关联

explain select * from teacher_student left join teacher on teacher_student.teacher_id = teacher.id;
explain select * from teacher_student left join student on teacher_student.student_id = student.id;

 ref:当用普通索引或者联合索引的左边部分字段与主表进行的关联或者做条件查询

explain select * from teacher where name = 'asd';
explain select teacher.id from teacher left join teacher_student on teacher.id = teacher_student.teacher_id;

 range:用主键索引或者普通索引进行范围搜索,比如>,=,<,between and,like  'x%'

explain select * from student where id > 1;
explain select * from teacher where name like 'x%';

index:这种虽然用到了索引,但是查询所有数据,在普通索引的索引树上的叶子节点查询所有,没有条件从而不会经过非叶子节点的筛选

explain select * from teacher;

ALL:这种是直接在主键索引上去找,而主键索引是聚簇索引树,包含所有数据,所以比index查找要慢

explain select * from student;

  • possible_key:可能用到的索引键,如果为Null说明可能不会用到索引
  • key:实际用到的索引键,如果为Null说明实际没用到索引
  • key_len:索引使用的字节数

计算规则:

        字符串类型

        char(n):3n个字节

        varchar(n):3n+2,加的2是用来存储字符串长度

        数值类型

        tinyint:1字节

        smallint:2字节

        int:4字节

        bigint:8字节

        实际类型

        date:3字节

        timestamp:4字节

        datetime8字节

  • ref:关联的表,通常展示const或者要查询列名
  • rows:查询表的扫描行数的估值
  • filtered:查询出来结果集占总扫描行数的百分比,结果越大说明扫描成本低
  • extra:

Using index:使用覆盖索引

用普通索引或者联合索引左边部分字段作为条件,当查询的字段在一颗普通索引树上的叶子节点上都有,这个时候可以说这条sql查询使用了覆盖索引

EXPLAIN select * from teacher where name = '123';
EXPLAIN select teacher_id,student_id from teacher_student where teacher_id = 1;

 Using where:使用where过滤的列未被索引覆盖

EXPLAIN select * from student where create_time = '2023-05-11 00:12:49';
EXPLAIN select * from student where name = 'test';

 

 Using index condition:查询的列没有被覆盖索引覆盖到,where是一个联合索引左边部分范围查找

explain select * from teacher_student where teacher_id > 1;

 Using temporary:查询时mysql自动建了一个临时表

explain select distinct name from student;#name无索引
explain select distinct name from teacher;#name有索引

 distinct会新建一张临时表做去重,可以使用索引做优化

 Using filesort:使用的是文件排序,这种排序非常慢的,可以使用索引排序,因为索引本身就是有序的数据结构

explain select * from student order by name;#name无索引
explain select * from teacher order by name;#name有索引

Select tables optimized away: 使用某些聚合函数(如:max、min)来访问某个存在索引字段

explain select min(id) from teacher;

二、索引基本优化示例

表:

DROP TABLE IF EXISTS `member`;
CREATE TABLE `member`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(0) NOT NULL DEFAULT 0 COMMENT '年龄',
  `address` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '地址',
  `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_name_age_address`(`name`, `age`, `address`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '会员记录表' ROW_FORMAT = Dynamic;

INSERT INTO `member` VALUES (5, 'LiLei', 22, 'manager', '2023-06-15 15:41:53');
INSERT INTO `member` VALUES (6, 'HanMeimei', 23, 'dev', '2023-06-15 15:41:53');
INSERT INTO `member` VALUES (7, 'Lucy', 23, 'dev', '2023-06-15 15:41:53');

1、全值匹配

EXPLAIN SELECT * FROM member WHERE name= 'test' order by name desc;
EXPLAIN SELECT * FROM member WHERE name= 'test' AND age = 22;
EXPLAIN SELECT * FROM member WHERE name= 'test' AND age = 22 AND address ='manager';

 name、age、address为联合索引,最好都能用作条件,可以减少非叶子节点load到内存IO次数,减少匹配次数,查询更快

2、不要在索引字段上加函数匹配,导致全表扫描

EXPLAIN SELECT * FROM member WHERE name = 'LiLei';
EXPLAIN SELECT * FROM member WHERE SUBSTR(1,2) = 'LiLei';

 给create_time添加一个普通索引

ALTER TABLE `member` ADD INDEX `create_time` (`create_time`) USING BTREE;
EXPLAIN select * from member where date(create_time) ='2018‐09‐30';#mysql8.0版本 类型校验不通过执行错误
EXPLAIN select * from member where date_format(create_time,'%Y-%m-%d') ='2018‐09‐30';

两个explain执行结果:

 timestamp日期类型转成varchar,如果类型都转变了,再去索引树上去找就会找不到,会导致全表扫描

3、联合索引中的列使用范围查询导致用不到后面的索引列

EXPLAIN SELECT * FROM member WHERE name= 'test' AND age = 22 AND address ='guangzhou';
EXPLAIN SELECT * FROM member WHERE name= 'test' AND age > 22 AND address ='guangzhou';

前一条sql索引全值匹配联合索引都会用到,后面sql因为是大于,非叶子节点之前没有指针,导致又需要从根节点重新加载匹配,或者因为范围太大导致,到address匹配时次数过多因而用不到address索引

4、尽量使用覆盖索引,只在二级索引树上查找效率快,查询所有的话要回表,效率慢

EXPLAIN SELECT name,age FROM member WHERE name= 'test' AND age = 23 AND address ='manager';
EXPLAIN SELECT * FROM member WHERE name= 'test' AND age = 23 AND address ='manager';

尽量使用第一条sql那样,把二级索引树上所有字段查询出来,这样可以不用回表,不要查所有,因为查询出来的所有记录都会回表

5、mysql中不要使用不等于、大于、小于、not in、not exists,查询范围大,用索引的话也差不多是全表扫描,最好控制条件范围,比如范围时间缩短、in条件减少

mysql8.0对not in、不等于做了优化,用了也会用到索引,mysql8.0之前的版本不会用到

EXPLAIN SELECT * FROM member WHERE name != '1';
EXPLAIN SELECT * FROM member WHERE name not in ('test','1','test','1','test','1','test','1','test','1','test','1','test','1');

mysql8.0结果:

6、is null,is not null一般情况下无法用到索引

EXPLAIN SELECT * FROM member WHERE name is null

7、条件查询不要用like '%x'

EXPLAIN SELECT * FROM member WHERE name like '%test';
EXPLAIN SELECT * FROM member WHERE name like 'test%';

最好用第二条sql ,因为前缀已经确定了大部分数据

8、条件值和字段类型不同导致索引失效

EXPLAIN SELECT * FROM member WHERE name = '1000';
EXPLAIN SELECT * FROM member WHERE name = 1000;

用1000数值类型去索引树上找不到,改成全表扫描 

9、少用or或in,还是范围过大,mysql根据成本计算,回表次数太多可能扫全表

mysql8.0对or和in都做了优化,能用到索引,之前的版本都可能用不到

EXPLAIN SELECT * FROM member WHERE name = 'test1' or name = 'test2';

mysql8.0执行结果:

10、范围查询优化


ALTER TABLE member ADD INDEX idx_age (age) USING BTREE ;
explain select * from member where age >=1 and age <=2000;
explain select * from member where age >=1 and age <=1000;
explain select * from member where age >=1001 and age <=2000;
ALTER TABLE member DROP INDEX `idx_age`;#删除索引

mysql8.0对这种也做了优化,可以用到索引,之前版本可能要拆成几段sql来查才能用到索引,像第二、三条sql一样

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

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

相关文章

市场·分析

寡头垄断市场 完全竞争市场 完全垄断 垄断竞争 博弈论与寡头竞争理论 寡头市场的特征&#xff1a; 少量的企业竞争策略互动纯寡头 -生产相同产品的企业 -市场上只有一个价格差异化寡头 -生产差异化产品的企业 -价格成为决策变量 博弈论基础 博弈论模型描述个体在知道他所采…

用flex布局实现一个流程设计器

最近接到一个需求&#xff0c;要做一个流程设计的功能&#xff0c;大概长下面这个样子&#xff1a; 支持添加、编辑和删除节点&#xff0c;节点只有四种类型&#xff1a;开始节点、普通节点、分支节点、结束节点。 因为每个节点只有一个进和一个出&#xff0c;且节点不需要支持…

一文扫盲 OA、CRM、ERP、MES、HRM、SCM、WMS、KMS 等B端系统

OA系统 &#xff08;Office Automation System&#xff0c;办公自动化系统&#xff09;&#xff1a;OA系统是一种用于协调、管理和优化办公流程的软件系统&#xff0c;包括电子邮件、日程安排、文档管理、工作流程管理等功能模块&#xff0c;帮助企业提高工作效率和管理水平。…

C#程序的内存映射文件解析

一、背景 前段时间训练营里有朋友问 内存映射文件 是怎么玩的&#xff1f;说实话这东西理论我相信很多朋友都知道&#xff0c;就是将文件映射到进程的虚拟地址&#xff0c;说起来很容易&#xff0c;那如何让大家眼见为实呢&#xff1f;可能会难倒很多人&#xff0c;所以这篇我…

《项目实战》构建SpringCloud alibaba项目

文章目录 1、概要2、整体架构流程2.1、技术结构组成部分 3、技术名词解释4、技术细节4.1、构建父工程4.1.1、选择构建Maven项目4.1.2、修改父工程文件4.1.3、修改父工程pom.xml配置4.1.3.1、添加springboot支持4.1.3.2、修改JDK版本、编码、springboot版本配置4.1.3.3、添加Spr…

自定义MaterialEditText

自定义MaterialEditText 日记 现在都不流行写博客了&#xff0c;因为这玩意都认为对于面试没啥用&#xff0c;我感觉很多事情不应该太功利。所谓博客还是更多的应该用来进行自己日常学习的归纳和总结&#xff0c;而不是去贪图所谓的面试加分。因为面试可能是一时的&#xff0…

Apple Vision Pro的价格并没有看起来那么疯狂

When Apple announced the price of their groundbreaking new mixed reality headset, the Vision Pro, jaws around the world collectively dropped. At a hefty $3,499, it’s not for everyone, but is it really so unreasonable if we take a closer look? 当苹果宣布其…

CSS特性、背景属性和显示模式

CSS特性 CSS特性&#xff1a;化简代码 / 定位问题&#xff0c;并解决问题 继承性层叠性优先级 继承性 继承性&#xff1a;子级默认继承父级的文字控制属性。 注意&#xff1a;如果标签有默认文字样式会继承失败。 例如&#xff1a;a 标签的颜色、标题的字体大小。 层叠性 …

前端 sentry 接入钉钉机器人

sentry 接入钉钉机器人 打开钉钉,添加机器人 此时会得到Webhook地址,记录一下,以后会用到 sentry 端设置 看看这里有木有钉钉插件,有的话开启插件,并配置这里我说一下没有的情况下,我们何如设置 这里需要填写webhook url 这个的url 需要是一个公网的地址,不可以是本地…

HID协议学习

HID协议学习 0. 文档资料 USB_HID协议中文版_USB接口HID设备_AUJsRmB9kg.pdf HID报告描述符精细说明_mgCxM8_ci9.pdf hut1_22_U3cvnwn_ZZ.pdf 1. 基本概念 HID协议是一种基于USB的通讯协议&#xff0c;用于在计算机和输入设备之间进行数据传输。HID协议定义了标准的数据格…

动态规划算法(子数组专题1)

动态规划算法专辑之子数组问题&#xff08;1&#xff09; 本专栏将从状态定义、状态转移方程、初始化、填表顺序、返回值这五大细节来详细讲述动态规划的算法的解题思路及代码实现一、什么是子数组 子数组&#xff1a;子数组是数组中的一个连续部分的集合&#xff0c;子序列可…

Python+Selenium UI自动化测试环境搭建及使用

目录 一、什么是Selenium &#xff1f; 二、Selenium环境搭建 三、WebDriver API 总结&#xff1a; 一、什么是Selenium &#xff1f; Selenium 是一个浏览器自动化测试框架&#xff0c;它主要用于web应用程序的自动化测试&#xff0c;其主要特点如下&#xff1a;开源、免费…

缅怀(上次写博客是2009年10月24日)

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Nucleo-F411RE (STM32F411)LL库体验 3 - 滴嗒定时器的配置

Nucleo-F411RE &#xff08;STM32F411&#xff09;LL库体验 3 - 滴嗒定时器的配置 1、LL库延时 LL库初始化时钟的时候调用了LL_Init1msTick(100000000)函数&#xff0c;这个函数其实就是初始化了系统的滴答定时器。 LL_InitTick原型如下&#xff1a; load值 sysclk/1000&a…

RocketMQ架构和工作流程

一.MQ概述 1.简介 MQ&#xff0c;Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件&#xff0c;是一套提供了消息生产、存储、消费全过程API的软件系统。消息即数据。一般消息的体量不会很大。 2.用途 限流削峰 MQ可以将系统的超量请求…

接口测试工具怎么选?这个技巧你一定要知道

目录 前言 一、易用性 二、灵活性 三、可靠性 测试用例 接口测试数据 自动化测试 测试报告 总结 前言 当今软性开发中&#xff0c;接口测试已成为必不可少的一环&#xff0c;该如何选择接口测试工具?选择合适的接口测试工具对于程房员来说非常重要&#xff0c;因为…

SQL死锁

前言&#xff1a; 使用脚本刷数据时&#xff0c;开多线程经常遇到死锁现象&#xff0c;面试也经常问到&#xff0c;故开此篇 日志错误示例&#xff1a; ### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock fo…

Tplink企业版开启ipv6

Tplink企业版开启ipv6 1、登录路由器 路由器的默认地址一般为&#xff1a;192.168.0.1&#xff0c;登录成功后如下图&#xff1a; 2、WAN设置ipv6 wan是设置启用ipv6模式&#xff0c;如果这里无法启用&#xff0c;主要是因为“接口模式”中启用了桥接模式&#xff0c;可以关闭…

多线程详解

多线程详解 Process和Thread 程序是指令和数据的有序结合&#xff0c;其本身没有任何运行的含义&#xff0c;是一个静态的概念 进程是执行程序的一次执行过程&#xff0c;是一个动态的概念&#xff0c;是系统资源分配的单位 通常在一个进程中可以包含若干个线程。线程是CPU调…

(数组) 922. 按奇偶排序数组 II ——【Leetcode每日一题】

❓922. 按奇偶排序数组 II 难度&#xff1a;简单 给定一个非负整数数组 nums&#xff0c; nums 中一半整数是 奇数 &#xff0c;一半整数是 偶数 。 对数组进行排序&#xff0c;以便当 nums[i] 为奇数时&#xff0c;i 也是 奇数 &#xff1b;当 nums[i] 为偶数时&#xff0c…