MySQL数据查询优化

MySQL调优是开发中必不可少的内容,以下是对MySQL查询性能优化的部分总结

1. explain关键字的使用

        explain关键字可以模拟优化器执行sql查询语句,获取sql的执行信息,使用方法:

explain+sql语句

        1.1 字段详解

        

  1.  id(select 查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序)

    ①id相同,执行顺序从上往下
    ②id全不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
    ③id部分相同,执行顺序是先按照数字大的先执行,然后数字相同的按照从上往下的顺序执行

  2. select_type(查询类型,用于区别普通查询、联合查询、子查询等复杂查询)
    SIMPLE :简单的select查询,查询中不包含子查询或UNION
    PRIMARY:查询中若包含任何复杂的子部分,最外层查询被标记为PRIMARY
    SUBQUERY:在select或where列表中包含了子查询
    DERIVED:在from列表中包含的子查询被标记为DERIVED,MySQL会递归执行这些子查询,把结果放在临时表里
    UNION:若第二个select出现在UNION之后,则被标记为UNION,若UNION包含在from子句的子查询中,外层select将被标记为DERIVED
    UNION RESULT:从UNION表获取结果的select

  3. table(显示这一行的数据是关于哪张表的)

  4. type(显示查询使用了那种类型,从最好到最差依次排列 system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
    system:表只有一行记录(等于系统表),是 const 类型的特例,平时不会出现
    ②const:表示通过索引一次就找到了,const 用于比较 primary key 或 unique 索引,因为只要匹配一行数据,所以很快,如将主键置于 where 列表中,mysql 就能将该查询转换为一个常量
    eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
    ref:非唯一性索引扫描,范围匹配某个单独值得所有行。本质上也是一种索引访问,他返回所有匹配某个单独值的行,然而,它可能也会找到多个符合条件的行,多以他应该属于查找和扫描的混合体
    range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是在你的where语句中出现了between、<、>、in等的查询,这种范围扫描索引比全表扫描要好,因为它只需开始于索引的某一点,而结束于另一点,不用扫描全部索引
    index:Full Index Scan,index于ALL区别为index类型只遍历索引树。通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
    ALL:Full Table Scan,将遍历全表找到匹配的行
     一般来说,得保证查询至少达到range级别,最好到达ref

  5. possible_keys(显示可能应用在这张表中的索引,一个或多个,查询涉及到的字段若存在索引,则该索引将被列出,但不一定被查询实际使用)

  6. key
    实际使用的索引,如果为NULL,则没有使用索引

    查询中若使用了覆盖索引,则该索引和查询的 select 字段重叠,仅出现在key列表中

  7. key_len
    用于处理查询的索引长度,表示索引中使用的字节数。通过这个值,可以得出一个多列索引里实际使用了哪一部分。

    注:key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。另外,key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中。

  8. ref

    显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值 ,如果可能,是一个常量const。

  9. rows

    表示MySQL根据表统计信息及索引选用情况,大致估算的找到所需的目标记录所需要读取的行数,不是精确值。这个值非常直观的显示 sql 效率好坏, 原则上 rows 越少越好

  10. filtered

    当你的索引统计直接获取了需要的所有数据时,就会显示100
    因此一个比较低filtered值表示需要有一个更好的索引,假如type=all,表示以全表扫描的方式得到1000条记录,且filtered=0.1%,表示只有1条记录是符合搜索条件的。

  11. extra

    Using filesort
    MySQL有两种方式可以生成有序的结果,通过排序操作或者使用索引,当Extra中出现了Using filesort 说明MySQL使用了后者,但注意虽然叫filesort但并不是说明就是用了文件来进行排序,只要可能排序都是在内存里完成的。大部分情况下利用索引排序更快,所以一般这时也要考虑优化查询了。使用文件完成排序操作,这是可能是ordery by,group by语句的结果,这可能是一个CPU密集型的过程,可以通过选择合适的索引来改进性能,用索引来为查询结果排序。

    Using temporary
    用临时表保存中间结果,常用于GROUP BY 和 ORDER BY操作中,一般看到它说明查询需要优化了,就算避免不了临时表的使用也要尽量避免硬盘临时表的使用。

    Not exists
    MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就不再搜索了。

    Using index
    说明查询是覆盖了索引的,不需要读取数据文件,从索引树(索引文件)中即可获得信息。如果同时出现using where,表明索引被用来执行索引键值的查找,没有using where,表明索引用来读取数据而非执行查找动作。这是MySQL服务层完成的,但无需再回表查询记录。

    Using index condition
    这是MySQL 5.6出来的新特性,叫做“索引条件推送”。简单说一点就是MySQL原来在索引上是不能执行如like这样的操作的,但是现在可以了,这样减少了不必要的IO操作,但是只能用在二级索引上。

    Using where
    使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。注意:Extra列出现Using where表示MySQL服务器将存储引擎返回服务层以后再应用WHERE条件过滤。

    Using join buffer
    使用了连接缓存:Block Nested Loop,连接算法是块嵌套循环连接;Batched Key Access,连接算法是批量索引连接

    impossible where
    where子句的值总是false,不能用来获取任何元组

    select tables optimized away
    在没有GROUP BY子句的情况下,基于索引优化MIN/MAX操作,或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。

    distinct
    优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作

    参考链接

2. MySQL索引原理

  • 顾名思义,B-tree索引使用B-tree的数据结构存储数据,不同的存储引擎以不同的方式使用B-Tree索引,比如MyISAM使用前缀压缩技术使得索引空间更小,而InnoDB则按照原数据格式存储,且MyISAM索引在索引中记录了对应数据的物理位置,而InnoDB则在索引中记录了对应的主键数值。B-Tree通常意味着所有的值都是按顺序存储,并且每个叶子页到根的距离相同。

  • B-Tree索引驱使存储引擎不再通过全表扫描获取数据,而是从索引的根节点开始查找,在根节点和中间节点都存放了指向下层节点的指针,通过比较节点页的值和要查找值可以找到合适的指针进入下层子节点,直到最下层的叶子节点,最终的结果就是要么找到对应的值,要么找不到对应的值。整个B-tree树的深度和表的大小直接相关。

  • 全键值匹配:和索引中的所有列都进行匹配,比如查找姓名为zhang san,出生于1982-1-1的人

  • 匹配最左前缀:和索引中的最左边的列进行匹配,比如查找所有姓为zhang的人

  • 匹配列前缀:匹配索引最左边列的开头部分,比如查找所有以z开头的姓名的人

  • 匹配范围值:匹配索引列的范围区域值,比如查找姓在li和wang之间的人

  • 精确匹配左边列并范围匹配右边的列:比如查找所有姓为Zhang,且名字以K开头的人

  • 只访问索引的查询:查询结果完全可以通过索引获得,也叫做覆盖索引,比如查找所有姓为zhang的人的姓名

参考链接

3. 实例
以下是我的测试表device_everyday_count_value的表结构:

CREATE TABLE `device_everyday_count_value` (`sid` int NOT NULL AUTO_INCREMENT COMMENT '主键 序号 自增',`device_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '设备id',`device_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '设备名称',`node_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '点位id',`node_describe` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '点位描述',`count_value` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '统计值',`latest_value` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '当天最新的(最晚的)记录',`value_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '信号值属性(dict_device_valuetype)',`count_date` date DEFAULT NULL COMMENT '统计时间',PRIMARY KEY (`sid`) USING BTREE,KEY `idx_deviceId_countDate_countValue` (`device_id`,`count_date`,`count_value`) USING BTREE COMMENT 'deviceId,countDate,CountValue普通索引'
) ENGINE=InnoDB AUTO_INCREMENT=515 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='设备点位每日用能统计表';

1.1 select * 

explain select t1.* from `device_everyday_count_value` t1;

 

根据上图能够发现当我们使用select *时,索引是失效的而且扫描了全表

现在改为如下所示:

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1;

发现索引生效了,所以应当避免使用select * 

1.2 where条件相等判断

explain select t1.device_id , t1.count_date from `device_everyday_count_value` t1 where t1.device_name = 'test';

发现没有走索引,且全表扫描。现改为如下所示:

explain select t1.device_id , t1.count_date from `device_everyday_count_value` t1 where t1.device_id = '20';

 

能够走索引,where过滤条件要符合最左原则。

1.3 回表

explain select  t1.device_name, t1.device_id, t1.count_date from `device_everyday_count_value` t1;

可以发现select字段中出现了没在索引列上的device_name,在执行的时候发现没有走索引并且type为all。现改为如下所示:

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1;

能够发现索引生效了,并且没有回表,表名我们在使用的过程中最好覆盖索引,如果是比较常用的name属性可以考虑走缓存,然后数据库查询的时候只查询device_id

1.4 type---查询范围优化

1.4.1 引号问题

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1 where t1.device_id > 1;

发现我们的type类型为index(system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL)是比较低的,

现改为如下所示:

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1 where t1.device_id > '1';

我们type类型变为了range类型,查询范围优化了,通过表结构能够发现我们的device_id是varchar类型的虽然数据库存储的是数字,但是类型是字符串类型的所以我们应该加上引号

1.4.2 索引顺序

在执行前先device_id的索引顺序移动到第二位

执行以下代码:

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1 where t1.device_id > '1';

接下来再将device_id的顺序移动到最后

执行同样的sql代码

explain select  t1.device_id, t1.count_date from `device_everyday_count_value` t1 where t1.device_id > '1';

可以发现我们的type的等级由range降为index了,索引我们在使用的时候需要符合最左前缀原则。

内容会持续更新,还会更新多表联合查询的优化处理以及注意事项!

锲而舍之,朽木不折;锲而不舍,金石可镂。——诗句出自:《荀子·劝学》

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

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

相关文章

智慧旅游推动旅游服务智慧化转型:借助智能科技的力量,实现旅游资源的精准匹配和高效利用,为游客提供更加便捷、舒适的旅游环境

目录 一、引言 二、智慧旅游的定义与特点 &#xff08;一&#xff09;智慧旅游的定义 &#xff08;二&#xff09;智慧旅游的特点 三、智能科技在旅游服务中的应用 &#xff08;一&#xff09;大数据分析助力旅游决策 &#xff08;二&#xff09;人工智能实现个性化推荐…

Linux提权--定时任务--打包配合 SUID(本地)文件权限配置不当(WEB+本地)

免责声明:本文仅做技术交流与学习... 目录 定时任务 打包配合 SUID-本地 原理: 背景: 操作演示: 分析: 实战发现: 定时任务 文件权限配置不当-WEB&本地 操作演示: 定时任务 打包配合 SUID-本地 原理: 提权通过获取计划任务执行文件信息进行提权 . 1、相对路径和…

STM32窗口看门狗的操作

STM32的窗口看门狗的主要功能是&#xff0c;程序过早的喂狗还有太晚喂狗&#xff0c;都会触发单片机重启&#xff0c;就是有一个时间段&#xff0c;在这个时间段内喂狗才不会触发单片机重启。 下面我就总结一下窗口看门狗的设置过程&#xff1a; 第一步&#xff1a;开启窗口看…

vs code中如何使用git

由于本地代码有了一些储备&#xff0c;所以想通过网址托管形式&#xff0c;之前一直使用了github&#xff0c;但是鉴于一直被墙&#xff0c;无法登录账号&#xff0c;所以选择了国内的gitee来作为托管网站。 gitee的网址&#xff1a;Gitee - 基于 Git 的代码托管和研发协作平台…

LVS DR模式部署

一、LVS 简介 LVS的三种工作模式 NAT 地址转换 调度器会作为所有节点服务器的默认网关&#xff0c;也是客户端的访问入口和节点服务器返回响应消息的出口&#xff0c;所以调度器会承载双向流量的负载压力&#xff0c;可能会为整个群集的性能瓶颈。由于节点服务器都会处于内网…

Linux下安装JDK并配置环境变量

一、Oracle官网下载jdk 1、官网地址 https://www.oracle.com/java/technologies/downloads/#java17 2、命令下载 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 3、解压 tar -zxvf jdk-17_linux-x64_bin.tar.gz 4、配置环境变量 ec…

Qt---窗口系统

一、QMainWindow QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏&#xff08;menu bar&#xff09;、多个工具栏(tool bars)、多个锚接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget) 1. 菜单栏(最多有一个) QMenuBar *bar…

自动秒收录网址导航分类目录模板

自动秒收录网址导航是一个以html5css3进行开发的免费版网址自动收录模板源码。 模板特点&#xff1a;全站响应式H5网站制作技术&#xff0c;一个网站适应不同终端&#xff0c;模板支持网址导航一键采集入库&#xff0c;免规则文章资讯智能批量采集内置伪原创&#xff0c;本地化…

windows11获取笔记本电脑电池健康报告

笔记本电脑的电池关系到我们外出时使用的安全&#xff0c;如果电池健康有问题需要及时更换&#xff0c;windows系统提供了检查电池健康度的方法。 1、打开命令行 1&#xff09;键入 winR 2&#xff09;键入 cmd 打开命令行。 2、在命令行运行如下指令&#xff0c;生成电池健…

springboot项目 字典/枚举翻译 终极解决方案 AOP+自定义注解+递归实体字段+实体动态三级缓存+责任链+多种转换方式

目录 前言实现思路技术确定 食用方式效果使用样例项目中使用第一步 复制包第二步 实现LoadDictDatabase并将其注入容器第三步 标识需要翻译的字段第四步 标识需要翻译的方法第五步 调用需要翻译的方法 实现细节TODO 前言 字典,即在存储介质中进行存储时,为了避免业务上对其名称…

【网站项目】SpringBoot803房屋租赁管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Day 28 MySQL的数据备份与恢复

数据备份及恢复 1.概述 ​ 所有备份数据都应放在非数据库本地&#xff0c;而且建议有多份副本 备份&#xff1a; 能够防止由于机械故障以及人为误操作带来的数据丢失&#xff0c;例如将数据库文件保存在了其它地方 冗余&#xff1a; 数据有多份冗余&#xff0c;但不等备份&…

【JUC】并发编程 Synchronized 锁升级原理

Synchronized如何实现同步/互斥的效果&#xff1f; monitorenter&#xff1a; 将锁对象对象头中Mark Word的前30bit替换成指向操作系统中与其关联的monitor对象&#xff0c;将锁记录位状态改为10 monitorexit&#xff1a; 将锁对象对象头中Mark Word进行重置&#xff0c;重新恢…

代码随想录——二叉树的层序遍历(Leetcode102)二叉树层序遍历的模板

题目链接 层序遍历&#xff08;队列&#xff09; 层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。 需要借用一个辅助数据结构即队列来实现&#xff0c;队列先进先出&#xff0c;符合一层一层遍历的逻辑&#xff0c;而用…

数据分享—全国分省河流水系

河流水系数据是日常研究中必备的数据之一&#xff0c;本期推文主要分享全国分省份的水系和河流数据&#xff0c;梧桐君会不定期的更新数据&#xff0c;欢迎长期订阅。 数据预览 山东省河流水系 吉林省河流水系 四川省河流水系 数据获取方式 链接&#xff1a;https://pan.baidu.…

# 电脑突然连接不上网络了,怎么办?

电脑突然连接不上网络了&#xff0c;怎么办&#xff1f; 一、原因分析&#xff1a; 1、IP 地址冲突 2、DNS 解析出现问题。 3、电脑网络设置是否打开了【移动热点】或【飞行模式】。 4、【WLAN AutoConfig】服务是否打开。 5、无线网卡驱动损坏。 6、检查 WIFI 开关是否…

【一步一步了解Java系列】:了解Java与C语言的运算符的“大同小异”

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努…

远程调用feign的使用

在orderservice子工程中 <!--feign的远程--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>启动类加上这个注解 EnableFeignClients //自动装配…

STM32系统架构

以下是STM32系统架构中的各个重要组件和功能&#xff1a; 组件描述Cortex-M内核ARM Cortex-M系列内核&#xff0c;如M0、M0、M3、M4、M7等Flash存储器存储程序代码和数据SRAM存储程序运行时数据和堆栈外设接口GPIO、SPI、I2C、UART、TIM、ADC、DAC、USB、CAN、Ethernet等时钟和…

微信小程序按钮去除边框线

通常我们去掉按钮边框直接设置 border:0 但是在小程序中无效&#xff0c;设置outline:none也没用&#xff0c;当然可能你会说加权重&#xff1b;试过了无效 实际上该样式是在伪元素::after内&#xff0c;主要你检查css 还看不到有这个关系&#xff0c;鹅厂就是坑多 类样式::…