Mysql进阶SQL优化

        SQL优化在开发场景中必不可少的技能之一,它能最大限度的提升SQL查询性能,如果随意使用也会出现不可预料的结局。

1、为什么要优化SQL

        我们先说说不优化SQL造成什么现象。常见问题是响应时间长,用户体验感低。数据库频繁争抢锁,浪费性能。CPU过载,资源消耗高等问题。为了避免这些问题,不能盲目的添加资源,尽可能做到物尽其用。现实生活中不管对于ToC还是ToB,对外核心点:体验感永远是排在第一位,不管系统好坏,一旦体验感不行,都会丧失客户,这也是我们需要去优化SQL的原因之一。

        优化SQL旨在保证提高数据库性能,提升应用程序响应速度,提升体验感。

2、怎么优化SQL

2.1、开启慢查询

a)查看Mysql是否开启慢查询,一般默认没有开启

## 查看慢查询开关命令
show variables like 'slow_query_log';

b)开启慢查询日志

1、在Mysql安装目录中找到my.ini文件

2、添加以下参数:

## 开启慢查询
slow_query_log = 1
## 存放目录
slow_query_log_file = D:\developDoc\slowQueryLog\slowlog.log
## 执行时间超过多少秒(单位秒)就会被记录到慢查询日志中
long_query_time = 1

3、重启Mysql服务。

## windows环境
1、services.msc
2、查询Mysql服务。
3、点击重启即可## linux环境
systemctl restart mysqld;

4、查询是否开启与存放路径。

b)查询语句(根据自身需求书写SQL)

c)查看慢查询日志

2.2、Profiling耗时分析(非必须)

        后续补充。

2.3、语句分析

        语句分析有两种命令方式:explain(常用),desc(一般用于查看表结构);除了关键字外不一样,其他的都一样。

2.3.1、Explain/Desc

        我们先看看explain执行语句长什么样子。在分析他们之间的关系与含义。

        图中可以看到 id, select_type,table,partitions,type,possible_keys,key,key_len,ref,rows,filtered,extra 这些字段,下面将分开讲述这些字段。

        SQL分析中必须查看 type、possible_keys、key、extra 四列,ken_len 其次,其他的可以根据需求查看。

2.3.1.1、id

        id:序号值,旨在控制执行顺序,值越大越先执行,值相同从上到下执行。

单行时,不用关注id数值,多行顺序值,需要关注执行顺序来分析SQL信息。

例如:

        查询中国银行中有多少用户,并提取用户信息。

select*
fromd_user du
wheredu.user_id in (selectdba.user_idfromd_bank_account dbawheredba.user_id = du.user_idand dba.bank_id = (selectdb.bank_idfromd_bank dbwheredb.bank_name = '中国银行')
) and du.id < 3;

        先看看原始SQL后(先心里有一个执行顺序),在配合explain中的序号和别名,看是否一致。 

        中国银行的储蓄用户,第一步:先查询中国银行id。第二部:在查询中国银行id对于的用户id。第三步:根据用户id,查询用户信息。根据步骤可以看出执行顺序:db,dba,du。explain执行顺序:3,2,1。可以看出结论与我们分析的一致,结论成立。

2.3.1.2、select_type

        select_type:搜索类型,常见类型 SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION等。

具体主要类型分析:

  • Simple(简单类型)
    • 简单的 SELECT 查询,不包含子查询或 UNION
  • PRIMARY(最外层查询)
    • 最外层查询,如果查询中包含任何复杂的子部分,最外层查询则被标记为 PRIMARY
  • SUBQUERY(子查询)
    • 在 SELECT 或 WHERE 列表中包含了子查询。
  • DERIVED
    • 在 FROM 列表中包含的子查询被标记为 DERIVED(衍生),MySQL 会递归执行这些子查询,把结果放在临时表里。
    • 后续补充
  • UNION
    • 如果第二个 SELECT 出现在 UNION 之后,则被标记为 UNION;若 UNION 包含在 FROM 子句的子查询中,外层 SELECT 将被标记为 DERIVED
    • 后续补充
  • UNION RESULT
    • 从 UNION 表获取结果的 SELECT
    • 后续补充
  • DEPENDENT SUBQUERY
    • 在 SELECT 或 WHERE 列表中包含了子查询,子查询基于外层。
    • 后续补充
  • UNCACHEABLE SUBQUERY
    • 无法被缓存的子查询。
    • 后续补充
2.3.1.3、table

        执行SQL所属表。

2.3.1.4、partitions

        匹配的分区信息。如果查询是基于分区表的话,会显示查询将访问的分区

2.3.1.5、type(类型)

        访问类型,如 ALL(全表扫描)、index(全索引扫描)、range(范围扫描)、ref(非唯一索引扫描)、eq_ref(唯一索引扫描),const(常量),system(系统) 等。

        性能从大到小  const > eq_ref > ref > range > index > all。如果Sql类型是 ALL 就必须优化,index 尽可能优化到range。

2.3.1.6、possible_keys

        SQL可能使用的索引,包含零个或多个。

2.3.1.7、key

        SQL使用的索引。

2.3.1.8、key_len

        SQL只用的索引长度。

2.3.1.9、ref

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

2.3.1.10、rows

        SQL执行影响行数,不是很准确。

2.3.1.11、filtered

        查询的表行占表的百分比。

2.3.1.12、extra

        拓展信息,也是SQL分析最重要的列。

3、常见SQL问题

3.1、未走索引,全表检索

        explain 中 type 显示 ALL 时 是没有走到索引的,具体可查看 key 列。

3.2、分组未走索引

        group by 中的字段没有建立索引,造成extra列显示 Using temporary 信息。

3.2、排序未走索引

        order by 中字段没有走索引。extra列显示 Using filesort 信息

3.3、索引失效

        字段建立索引没有走到。type 值显示 ALL

4、优化策略

4.0、数据结构

CREATE TABLE `d_user` (`id` int NOT NULL COMMENT '主键id',`user_id` varchar(50) NOT NULL COMMENT '用户id',`user_name` varchar(100) NOT NULL COMMENT '用户名',`phone` varchar(100) NOT NULL,`age` int NOT NULL,`gender` tinyint DEFAULT '0' COMMENT '性别',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`test_not_null` varchar(10) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `idx_user_qe_user_id` (`user_id`),KEY `idx_phone` (`phone`)
) ENGINE=InnoDB COMMENT='用户信息表';CREATE TABLE `d_bank` (`id` int NOT NULL COMMENT '主键id',`bank_id` varchar(50) NOT NULL COMMENT '银行id',`bank_name` varchar(50) NOT NULL COMMENT '银行名',`address` varchar(255) DEFAULT NULL COMMENT '地址',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='银行表';CREATE TABLE `d_bank_account` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',`account_id` varchar(50) NOT NULL COMMENT '银行卡id',`account_no` varchar(50) NOT NULL COMMENT '银行卡编号',`account_type` tinyint DEFAULT '0' COMMENT '银行卡类型',`bank_id` varchar(50) DEFAULT NULL COMMENT '银行卡id',`user_id` varchar(50) DEFAULT NULL COMMENT '持有人',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB comment='用户储蓄账号关系表';

4.1、策略方向

        1、经常搜索列建立索引。2、最左前缀匹配法则。3、索引覆盖。

        我们回顾哈上篇文章的索引:主键索引、唯一索引、普通索引(单列索引、联合索引)、全文索引(一般不用)

        建议:尽可能新建联合索引,少新建单列索引,能走主键索引绝不走唯一索引或普通索引(避免回表查询)。

4.2、问题分析

4.2.0、前序信息

表信息索引信息索引截图数据量
d_user999803
d_bank5
d_bank_account2774925

查看索引语法:

## 查询表索引
## table_name 数据表
show index from table_name;

4.2.1、未走索引现象与优化

案例一:查询手机号='13500000215'用户信息

语句:select * from d_user where phone = '13500000215';

数据:可以看出执行耗时1.5秒

 explain分析:可以看出 type = ALL 且 key = null 没有走索引。

对phone字段添加索引: 

        图中可知:type 由 all 优化为了 ref , key 也使用了刚刚新建索引,整个耗时由 1.5秒提升至 忽略不计。

案例二:查询user_id=4a163cc6e18341698bc9b3a8ce64ee88用户信息

        图中可知:耗时1.5秒左右。

        分析:用户id在整个系统中应该唯一,不可能出现所谓了重复问题,所以对user_id字段添加唯一索引。

 总结:通过上面两个案例可知,走索引与不走索引的性能差异之大,其中唯一索引性能提升最大,type 等于了 const,这也是 SQL优化中 最优解,但是这个类型只有唯一索引与主键索引可以达到,其他的索引最多只能达到eq_ref ,索引优化中常见是 ref 是最优。

4.2.2、走索引缺失效与优化

        索引失效常见有如下几种场景:

4.2.2.1、未走 最左前缀匹配法则,导致索引失效。

        可以看出 age 字段在联合索引中,但是

4.2.2.2、范围查询列之后列,不走索引。
4.2.2.2.1、案例分析

        是否失效需要查看联合索引中各个字段的索引长度:

        a)先看看全匹配联合索引的索引长度:key_len = 408

        b) 查看gender索引长度:408 - 106 = 2

        c)查看age与user_name索引长度:age :408 - 402 = 6。user_name : 402

         从上面三个步骤来看三个字段索引长度,usename = 402, age = 6, gender = 2

 案例一:查看姓名=‘测试用户2’ 且 年龄>20 且 性别=1;

         图中可知:索引长度 = 406 缺少了 gender的索引长度(失效)。

        解决方式:范围查询 更改 范围查询+等值查询。例如: > 更改 >= , < 更改 <=等。

 下图可知:将 > 更改为 >= 后,走全索引。

4.2.2.2.2、结论

         范围查询 需要将 > ,< 更换为 >=, <=来走索引。

4.2.2.3、全模糊或前缀模糊不走索引。
4.2.2.3.1、案例分析

案例一:查询姓名包含测试用户的储蓄用户。

案例二:查询已123结尾的储蓄用户。

4.2.2.3.2、结论

        从上面两个案例来看,对于字符类型的模糊匹配会造成索引失效(不走索引)。

解决方式:采用后缀匹配 即 like 'xxx%';

        图中可知:后缀模糊匹配与等值匹配都走索引,且索引长度一致,除type不一致外。

4.2.2.4、函数计算索引失效。
4.2.2.4.1、案例分析

案例一:查询用户姓名长度大于7的信息

案例二:查询以前2个字符为前缀匹配

4.2.2.4.2、结论

        从上面两个案例来看,对于使用计算函数列无法采用索引。

解决方式:1、创建函数索引(8.0引入)。2、索引覆盖

4.2.2.5、or条件索引失效
4.2.2.5.1、案例分析

案例一:前面条件走索引字段 or 条件字段不是索引字段

案例二:前面条件走索引 or 条件字段索引失效 

4.2.2.5.2、结论

        从上面两个案例可知:一旦 or中某一条件索引失效,整个SQL的索引都失效。

解决方法:or 前后条件都走索引。

5、总结

        本文还未完善,后续会补充 多表关联讲解。

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

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

相关文章

修改成清华镜像源解决Anaconda报The channel is not accessible源通道不可用问题

修改成清华镜像源解决Anaconda报The channel is not accessible源通道不可用问题 最近在通过pycharm开发python程序&#xff0c;引用anaconda环境建立虚拟环境时报错&#xff0c;报UnavailableInvalidChannel: The channel is not accessible or is invalid.应该是镜像源访问通…

年会游戏策划

一、游戏名称 单眼弹瓶盖 二、游戏目的 通过单眼瞄准方式&#xff0c;锻炼玩家的手眼协调能力和注意力。 三、游戏规则 1. 参与者需站在一定距离外&#xff0c;遮住左眼睛&#xff0c;先转三圈&#xff0c;走到瓶子前&#xff0c;将瓶子上没有拧紧的瓶盖用…

【Linux】flock 文件级别的锁定

flock 是 Linux/Unix 系统中的一个命令&#xff0c;用于实现文件级别的锁定。它允许你在多个进程之间共享对文件的访问&#xff0c;但确保在同一时间只有一个进程可以访问文件&#xff0c;避免竞态条件&#xff08;race conditions&#xff09;和数据不一致问题。 flock 的基本…

Selenium+Java(21):Jenkins发送邮件报错Not sent to the following valid addresses解决方案

问题现象 小月妹妹近期在做RobotFrameWork自动化测试,并且使用Jenkins发送测试邮件的时候,发现报错Not sent to the following valid addresses,明明各个配置项看起来都没有问题,但是一到邮件发送环节,就是发送不出去,而且还不提示太多有用的信息,急的妹妹脸都红了,于…

Redis6为什么引入了多线程?

大家好&#xff0c;我是锋哥。今天分享关于【Redis6为什么引入了多线程&#xff1f;】面试题。希望对大家有帮助&#xff1b; Redis6为什么引入了多线程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 6 引入了多线程的主要目的是提高性能&#…

【模块一】kubernetes容器编排进阶实战之kubernetes 资源限制

kubernetes 资源限制 kubernetes中资源限制概括 1.如果运行的容器没有定义资源(memory、CPU)等限制&#xff0c;但是在namespace定义了LimitRange限制&#xff0c;那么该容器会继承LimitRange中的 默认限制。 2.如果namespace没有定义LimitRange限制&#xff0c;那么该容器可…

Rancher V2.9.0 Docker安装教程

1、创建Rancher挂载目录 mkdir -p /home/rancher/k3s/agent/images/ 2、复制容器中的镜像tar包&#xff0c;防止挂载之后镜像包丢失导致创建集群报错 避免&#xff1a;Internal error occurred: failed calling webhook "default.cluster.cluster.x-k8s.io" dock…

pytorch将数据与模型都放到GPU上训练

默认是CPU&#xff0c;如果想要用GPU需要&#xff1a; 安装配置cuda&#xff0c;然后更新/下载支持gpu版本的pytorch&#xff0c;可以参考&#xff1a;https://blog.csdn.net/weixin_35757704/article/details/124315569设置device&#xff1a;device torch.device(cuda if t…

CPT203 Software Engineering 软件工程 Pt.1 概论和软件过程(中英双语)

文章目录 1.Introduction1.1 What software engineering is and why it is important&#xff08;什么是软件工程&#xff0c;为什么它很重要&#xff09;1.1 We can’t run the modern world without software&#xff08;我们的世界离不开软件&#xff09;1.1.1 What is Soft…

MongoDB 创建用户、User、Role 相关 操作

创建用户 # db.createUser() Creates a new user.详细 查看 db.createUser() - MongoDB Manual v8.0 设置用户 Role&#xff08;创建用户时也可以设置&#xff09; # db.grantRolesToUser() Grants a role and its privileges to a user. 详细 查看 db.grantRolesToUser(…

v-if 和 v-show 的区别

一、原理区别 1. v-if 这是一个指令&#xff0c;用于条件性地渲染一个元素块。当v-if表达式的值为true时&#xff0c;元素及其包含的子元素才会被渲染到 DOM 中&#xff1b;当表达式的值为false时&#xff0c;元素及其子元素会被完全移除。这意味着在切换v-if的条件时&#x…

从 Coding (Jenkinsfile) 到 Docker:全流程自动化部署 Spring Boot 实战指南(简化篇)

前言 本文记录使用 Coding (以 Jenkinsfile 为核心) 和 Docker 部署 Springboot 项目的过程&#xff0c;分享设置细节和一些注意问题。 1. 配置服务器环境 在实施此过程前&#xff0c;确保服务器已配置好 Docker、MySQL 和 Redis&#xff0c;可参考下列链接进行操作&#xff1…

[WASAPI]音频API:从Qt MultipleMedia走到WASAPI,相似与不同

[WASAPI] 从Qt MultipleMedia 来看WASAPI 最近在学习有关Windows上的音频驱动相关的知识&#xff0c;在正式开始说WASAPI之前&#xff0c;我想先说一说Qt的Multiple Media&#xff0c;为什么呢&#xff1f;因为Qt的MultipleMedia实际上是WASAPI的一层封装&#xff0c;它在是线…

绝美的数据处理图-三坐标轴-散点图-堆叠图-数据可视化图

clc clear close all %% 读取数据 load(MyColor.mat) %读取颜色包for iloop 1:25 %提取工作表数据data0(iloop) {readtable(data.xlsx,sheet,iloop)}; end%% 解析数据 countzeros(23,14); for iloop 1:25index(iloop) { cell2mat(table2array(data0{1,iloop}(1,1)))};data(i…

SVN和Git

SVN&#xff08;Subversion&#xff09;和 Git 都是流行的版本控制系统&#xff08;VCS&#xff09;&#xff0c;但它们在架构、使用场景、功能等方面有所不同。以下是它们的主要区别、各自的好处以及如何使用它们的详细说明。 一、SVN 和 Git 的区别 1. 版本控制模型 SVN&…

Spring Boot自定义注解获取当前登录用户信息

写在前面 在项目开发过程中&#xff0c;难免都要获取当前登录用户的信息。通常的做法&#xff0c;都是开发一个获取用户信息的接口。 如果在本项目中&#xff0c;多处都需要获取登录用户的信息&#xff0c;难不成还要调用自己写的接口吗&#xff1f;显然不用&#xff01; 以…

第三百四十六节 JavaFX教程 - JavaFX绑定

JavaFX教程 - JavaFX绑定 JavaFX绑定同步两个值&#xff1a;当因变量更改时&#xff0c;其他变量更改。 要将属性绑定到另一个属性&#xff0c;请调用bind()方法&#xff0c;该方法在一个方向绑定值。例如&#xff0c;当属性A绑定到属性B时&#xff0c;属性B的更改将更新属性A…

详解VHDL如何编写Testbench

1.概述 仿真测试平台文件(Testbench)是可以用来验证所设计的硬件模型正确性的 VHDL模型&#xff0c;它为所测试的元件提供了激励信号&#xff0c;可以以波形的方式显示仿真结果或把测试结果存储到文件中。这里所说的激励信号可以直接集成在测试平台文件中&#xff0c;也可以从…

深度学习:从原理到搭建基础模型

引言: 深度学习为什么火? 深度学习在处理复杂的感知和模式识别任务方面展现出了前所未有的能力。以图像识别为例,深度学习模型(如卷积神经网络 CNN)能够识别图像中的各种物体、场景和特征,准确率远超传统的计算机视觉方法。 当然这之中也还因为 大数据时代的推动(随着…

c语言中void关键字的含义和用法

在 C 语言中&#xff0c;void 是一个特殊的关键字&#xff0c;主要有以下几个用途&#xff1a; 1. 表示函数没有返回值 当一个函数不需要返回任何值时&#xff0c;可以将其返回类型声明为 void。 #include <stdio.h>void printMessage() {printf("Hello, World!\…