记录一次mysql慢查询的优化过程

news2024/9/27 7:22:43

前言

业务上线后经常报查询超时,数据库使用的是阿里云的RDS,mysql版本是5.6.16-log,有几条统计数据的查询语句执行很慢,有的甚至执行一次需要10多秒,简直无法忍受。
查看了超时时间,默认为0

show variables like '%MAX_STATEMENT_TIME%'
show variables like '%MAX_EXECUTION_TIME%'
# 网上说这个参数只针对5.7以上的版本生效
SET GLOBAL MAX_EXECUTION_TIME=30000;
# 对5.6版本生效
SET GLOBAL MAX_STATEMENT_TIME=30000;

然后在 select 后面 加上 /*+ max_statement_time(1000) */
设置后也没有效果,然后在阿里云上面手动修改对应的参数,也没用。

最后在阿里云上面看到几条优化建议,参考阿里云的建议,查询速度明显提升,这里也记录一下。

例1

表里面有810w+的数据
在这里插入图片描述

  1. 首先,就是建立正确的索引。
    多创建了两个联合索引,第一个是之前创建的,虽然能命中,但不是最佳。
ALTER TABLE `user_event_record` ADD INDEX `idx_event_gmtcreate_userid` (`event`, `gmt_create`, `user_id`)	
ALTER TABLE `user_event_record` ADD INDEX `idx_gmtcreate_event` (`gmt_create`, `event`)

在这里插入图片描述
2. 修改时间查询条件

  • 原sql
SELECT 
	LEFT (f.gmt_create, 10 ) `date`,
	f.event,
	COUNT(1) total 
FROM user_event_record f 
WHERE
	date_format(f.gmt_create, '%y%m%d') >= date_format('2023-01-14', '%y%m%d') 
GROUP BY `date`, f.event;
  • 修改后的sql
SELECT 
	LEFT (f.gmt_create, 10) `date`,
	f.event,
	COUNT(1) total 
FROM user_event_record f 
WHERE
	f.gmt_create > DATE('2023-01-14') 
GROUP BY `date`, f.event;

查询速度对比

  • 原sql执行时间
    在这里插入图片描述

  • 修改后的sql执行时间
    在这里插入图片描述

直接提升了7-8倍,查询结果一致,效果提升还是很明显的。

例2

同一个表
原SQL

SELECT
		DATE_FORMAT(gmt_create, '%m-%d') AS `time`,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' OR event = 'enterSystemSuc' THEN user_id END) AS total,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' THEN user_id END) AS success,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' THEN user_id END) AS fail,
		COUNT(DISTINCT CASE WHEN app = '1.0.7' and (event = 'enterSystemFail' OR event = 'enterSystemSuc') THEN user_id END) AS oldCount,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' AND app = '1.0.7' THEN user_id END) AS oldSuccess,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' AND app = '1.0.7' THEN user_id END) AS oldFail,
		COUNT(DISTINCT CASE WHEN app = '1.0.8' and (event = 'enterSystemFail' OR event = 'enterSystemSuc') THEN user_id END) AS newCount,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' AND app = '1.0.8' THEN user_id END) AS newSuccess,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' AND app = '1.0.8' THEN user_id END) AS newFail
FROM user_event_record
WHERE DATE_FORMAT(gmt_create, '%Y-%m-%d') > DATE_SUB(CURDATE(), INTERVAL 10 DAY)
GROUP BY DATE_FORMAT(gmt_create, '%m-%d')

修改后的sql

SELECT
		DATE_FORMAT(gmt_create, '%m-%d') AS `time`,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' OR event = 'enterSystemSuc' THEN user_id END) AS total,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' THEN user_id END) AS success,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' THEN user_id END) AS fail,
		COUNT(DISTINCT CASE WHEN app = '1.0.7' and (event = 'enterSystemFail' OR event = 'enterSystemSuc') THEN user_id END) AS oldCount,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' AND app = '1.0.7' THEN user_id END) AS oldSuccess,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' AND app = '1.0.7' THEN user_id END) AS oldFail,
		COUNT(DISTINCT CASE WHEN app = '1.0.8' and (event = 'enterSystemFail' OR event = 'enterSystemSuc') THEN user_id END) AS newCount,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemSuc' AND app = '1.0.8' THEN user_id END) AS newSuccess,
		COUNT(DISTINCT CASE WHEN event = 'enterSystemFail' AND app = '1.0.8' THEN user_id END) AS newFail
FROM user_event_record
WHERE gmt_create > DATE_SUB(CURDATE(), INTERVAL 9 DAY)
GROUP BY DATE_FORMAT(gmt_create, '%m-%d')

查询速度对比

  • 原sql执行时间
    在这里插入图片描述
  • 修改后的sql执行时间
    在这里插入图片描述
    从28秒提升到3秒,提升了8-9倍

例3

表数据530w+
在这里插入图片描述
创建了联合索引

ALTER TABLE `file_record_info` ADD INDEX `idx_mark_gmtcreate_userid` (`mark`, `gmt_create`, `user_id`)

在这里插入图片描述

  • 原sql
SELECT
	'2023-01-12' AS `date`,
	COUNT(DISTINCT CASE WHEN `mark` = '10000' THEN `user_id` ELSE NULL END) AS `upgradeFailCount`,
	COUNT(DISTINCT CASE WHEN `mark` = '10001' THEN `user_id` ELSE NULL END) AS `enterSysFailCount`,
	COUNT(DISTINCT CASE WHEN `mark` = '10008' THEN `user_id` ELSE NULL END) AS `dllLoadFailCount`,
	COUNT(DISTINCT CASE WHEN `mark` = '10009' THEN `user_id` ELSE NULL END) AS `enableDeviceFailCount`	
FROM file_record_info 
WHERE 
	mark IN ('10000', '10001', '10008', '10009' ) 
	AND DATE_FORMAT(gmt_create, '%Y-%m-%d') = '2023-01-12';
  • 修改后的sql
SELECT
	'2023-01-12' AS `date`,
	COUNT(DISTINCT CASE WHEN mark = '10000' THEN user_id END) AS upgradeFailCount,
	COUNT(DISTINCT CASE WHEN mark = '10001' THEN user_id END) AS enterSysFailCount,
	COUNT(DISTINCT CASE WHEN mark = '10008' THEN user_id END) AS dllLoadFailCount,
	COUNT(DISTINCT CASE WHEN mark = '10009' THEN user_id END) AS enableDeviceFailCount
FROM file_record_info WHERE mark IN ( '10000', '10001', '10008', '10009' )
AND (`gmt_create` >= DATE('2023-01-12') AND `gmt_create` < DATE_ADD(DATE('2023-01-12'), INTERVAL 1 DAY));

查询速度对比

  • 原sql执行时间
    在这里插入图片描述
  • 修改后的sql执行时间
    在这里插入图片描述
    提升约30倍

例4

同样的例子

SELECT
/*+ MAX_EXECUTION_TIME(20000) */
	'2023-01-15' AS `date`,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemFail' OR `event` = 'enterOBDSystemSuc' THEN user_id END ) AS total,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemSuc' THEN user_id END ) AS success,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemFail' THEN user_id END ) AS fail 
FROM user_event_record 
WHERE
	`event` IN ( 'enterOBDSystemFail', 'enterOBDSystemSuc' ) 
	AND DATE_FORMAT( gmt_create, '%Y-%m-%d' ) = '2023-01-15';
  • 修改后的sql
SELECT
	'2023-01-15' AS `date`,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemFail' OR `event` = 'enterOBDSystemSuc' THEN `user_id` ELSE NULL END ) AS `total`,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemSuc' THEN `user_id` ELSE NULL END ) AS `success`,
	COUNT( DISTINCT CASE WHEN `event` = 'enterOBDSystemFail' THEN `user_id` ELSE NULL END ) AS `fail` 
FROM `user_event_record` 
WHERE
	`event` IN ( 'enterOBDSystemFail', 'enterOBDSystemSuc' ) 
	AND `gmt_create` >= DATE( '2023-01-15' ) 
	AND `gmt_create` < DATE_ADD( DATE( '2023-01-15' ), INTERVAL 1 DAY ); 

查询速度对比

  • 原sql执行时间
    在这里插入图片描述
  • 修改后的sql执行时间
    在这里插入图片描述
    提升约40倍

例5

  • 原sql
SELECT
	IFNULL( DATE_FORMAT( gmt_create, '%Y-%m-%d' ), '2022-12-01' ) `date`,
	COUNT( DISTINCT CASE WHEN mark = '10000' THEN user_id END ) AS upgradeFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10001' THEN user_id END ) AS enterSysFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10008' THEN user_id END ) AS dllLoadFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10009' THEN user_id END ) AS enableDeviceFailCount 
FROM file_record_info 
WHERE
	mark IN ('10000', '10001', '10008', '10009') 
	AND DATE_FORMAT(gmt_create, '%Y-%m-%d')>='2022-12-01'
GROUP BY `date`
  • 修改后的sql
SELECT
	IFNULL( DATE_FORMAT( gmt_create, '%Y-%m-%d' ), '2022-12-01' ) `date`,
	COUNT( DISTINCT CASE WHEN mark = '10000' THEN user_id END ) AS upgradeFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10001' THEN user_id END ) AS enterSysFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10008' THEN user_id END ) AS dllLoadFailCount,
	COUNT( DISTINCT CASE WHEN mark = '10009' THEN user_id END ) AS enableDeviceFailCount 
FROM file_record_info 
WHERE
	mark IN ('10000', '10001', '10008', '10009') 
	AND gmt_create > DATE('2022-12-01') 
GROUP BY `date`

查询速度对比

  • 原sql执行时间
    在这里插入图片描述
  • 修改后的sql执行时间
    在这里插入图片描述
    有所提升。

总结

  1. 首先索引一定要根据业务来创建,不然没办法命中,可以通过EXPLAIN关键字来分析。
  2. 尽量避免DATE_FORMAT函数

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

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

相关文章

【微信小程序-原生开发】实用教程03-自定义底部导航(含自定义tabBar导航高亮需点击两次的解决方案)

开始前&#xff0c;请先完成底部导航的开发&#xff0c;详见 【微信小程序-原生开发】实用教程02-添加全局页面配置、页面、底部导航 https://sunshinehu.blog.csdn.net/article/details/128705866 显然&#xff0c;纯文字的底部导航有点low&#xff0c;还是需要有图标的才酷…

新手编写IntelliJ IDEA插件

需求目的可能你会想什么场景会需要用到插件开发&#xff0c;其实插件开发算是一种通用的解决方案&#xff0c;由服务平台定义标准让各自使用方进行自需的扩展。这就像我们非常常用的 P3C 代码检查插件、代码审计插件、脚手架工程创建插件、自动化API提取插件、单元测试统计插件…

TOF相机国产、非国产统计参数对比分析

TOF相机国产、非国产统计参数对比分析 Kinect v2 Kinect v2是Microsoft在2014年发售的&#xff0c;如图1-1所示。相比于Kinect v1在硬件和软件上作出了很大的进化&#xff0c;且在深度测量的系统和非系统误差方面表现出更好的性能。 Kinect v2中一共有三个摄像头&#xff0c…

Linux学习笔记【part2】网络配置与远程登录

Linux基础篇学习笔记 1.网络连接模式 VMware 提供了三种网络连接模式&#xff1a; ① 桥接模式 桥接模式&#xff1a;虚拟机直接连接外部物理网络的模式&#xff0c;主机起到了网桥的作用。在这种模式下&#xff0c;虚拟机可以直接访问外部网络&#xff0c;并且对外部网络是…

vue3利用keepAlive缓存页面

场景介绍 项目中经常会有这么一个需求&#xff0c;一个表单页面&#xff0c;可能需要跳转其他页面拿到对应的数据&#xff0c;再跳回表单页面&#xff0c;但是之前填写过的数据还在。而某些页面跳这个表单页面的时候&#xff0c;是不需要缓存&#xff0c;因为他是新增&#xf…

通过Facebook建立反链:SEO角度

最近我有一个朋友的网站做得很不错&#xff0c;每天都在增加反链。反链对于网站来说&#xff0c;好处是显而易见的&#xff0c;能够提升搜索引擎对网站的认可度&#xff0c;增强用户对网站的信任度。另外一个方面的好处是&#xff0c;反链可以提高流量&#xff08;或者转化率&a…

想考个PMP证书,要怎么报考?

pmp 报考条件没他们说的那么难&#xff0c;什么 4500/7500 个小时的项目管理经验&#xff0c;这个条件看起来很难&#xff0c;其实项目无处不在&#xff0c;画一幅画&#xff0c;做一餐饭&#xff0c;都能算一个项目&#xff0c;这 4500个小时、7500 个小时很快就达到了。一、报…

三十、Kubernetes中kube-proxy三种工作模式详解

1、概述 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题&#xff0c;kubernetes提供了Service资源&…

2023-01-18 ClickHouse之聚合功能源码分析

前言 聚合分析是从海量数据中提取数据的基本方法&#xff0c;对于OLAP数据库而言&#xff0c;聚合分析是其关键能力之一&#xff0c;ClickHouse在这方面也做了很多设计和优化&#xff0c;正如ClickHouse在文档中所述&#xff1a; 本文将分析展示ClickHouse的聚合功能的工作原理…

NFS 导出的共享信息披露漏洞问题解法

输入&#xff1a;shoumount -e&#xff0c; 如果有目录信息&#xff0c;则说明有NFS 导出的共享信息披露漏洞。 如果处理了就应显示如下图&#xff1a; 解法如下&#xff1a; 1&#xff09;备份需要修改的文件 cp /etc/hosts.allow /etc/hosts.allowbak cp /etc/hosts.deny…

前端js实现文件多次添加累加上传和选择删除(django+js)

前言 原本的多文件上传功能在选择文件时&#xff0c;只能通过同一范围的鼠标框选或者ctrl/shift多选取选择文件&#xff0c;这样选择文件很不灵活&#xff0c;而且在确定之后如果漏选了文件&#xff0c;再次点击上传按钮时会清空表单里的文件信息&#xff0c;只能重复之前的操…

springcloudalibaba整合nacos

文章目录1.版本配置2.搭建项目2.1idea新建项目2.2项目依赖2.3测试初始项目2.4项目的配置文件3.nocas的配置文件4.进行测试4.1准备测试的文件4.2测试nacos安装&#xff1a; nacos下载安装 1.版本配置 2.搭建项目 2.1idea新建项目 选择springcloudalibaba和springboot版本 spr…

Minecraft 1.19.2 Forge模组开发 10.3D动画盔甲

Minecraft 1.16.5模组开发3D盔甲 Minecraft 1.12.2模组开发3D盔甲 Minecraft 1.18.2模组开发3D动画盔甲 我们本次在1.19.2的版本中实现具有动画效果的3D盔甲 效果演示效果演示效果演示 1.首先&#xff0c;为了实现这些效果&#xff0c;我们需要首先使用到一个模组:geckolib…

剖析栈和队列OJ题

1.括号匹配问题给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。有效字符串需满足&#xff1a;1.左括号必须用相同类型的右括号闭合。2.左括号必须以正确的顺序闭合。3.每个右括号都有一个对应…

【阅读笔记】c++ Primer Plus——第八章

函数探幽 c内联函数 为了提高程序运行速度而做的改进编译的最终产物是可执行程序——由一组机器语言指令组成。运行程序时&#xff0c;操作系统将这些指令载入到计算机内存中&#xff0c;因此每条指令都有特定的内存地址。然后计算机开始逐步执行指令。执行到函数调用的时候&…

一道编程劝退题,检测你是否适合干编程

前言大家都知道要想成为一名优秀的开发工程师&#xff0c;需要数学基础好&#xff0c;即你要有很强的逻辑思维能力&#xff0c;这里有一道美国斯坦福大学出的一道逻辑思维的测试测试&#xff0c;检测你的逻辑思维能力&#xff0c;大家可以看看自己逻辑能力怎么样。题目有一个抽…

<队列>的概念结构实现【C语言版】

1.队列的概念及结构 队列对于临时数据的处理也十分有趣&#xff0c;它跟栈一样都是有约束条件的数组&#xff08;或者链表&#xff09;。区别在于我们想要按什么顺序去处理数据&#xff0c;而这个顺序当然是要取决于具体的应用场景。 你可以将队列想象成是电影院排队。排在最…

Android Studio 工程导入 AOSP编译的 android.jar

使用场景   1.需要使用 framework 中的 SystemApi 文件或者 hide 的 API 接口   2.定制 Framework 层业务&#xff0c;即有 客制化 的 API 接口 补充知识点   1.framework 源码即 AS 工程目录中 External Libraries 下的 < Android API xx Platform > 下的原生 SDK…

Docker-全面详解(学习总结---从入门到深化)

一、什么是Docker Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 什么是"集装箱技术" 我们都知道码头里的集装箱是运载货物用的&#xff0c;它是一种按规格标准 化的钢制箱子。集装箱的特色&#xff0c;在于其格式划一&…

峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?

小游戏《羊了个羊》 短短的7天内&#xff0c;DAU突破了1亿、吞吐量峰值21WQps。 《羊了个羊》运营后台数据显示&#xff0c;在短短的7天内&#xff0c;这款小游戏的DAU就突破了1亿。 要知道&#xff0c;除了王者荣耀、原神等屈指可数的现象级手游之外&#xff0c;1亿DAU是这个…