​【香菇带你学Mysql】Mysql超长执行sql定位和优化【建议收藏】

本文为MySQL数据库管理员和开发人员提供了一套全面的超时SQL定位和优化解决方案。通过合理运用这些方法和技巧,可以显著提升MySQL数据库的性能和稳定性,减少超时SQL语句的发生,确保数据库的高效运行。

0. 引言

最近某个Mysql数据库频繁告警,监控系统提醒有执行时间超长sql(基本上是执行时间超过1800秒)的语句。

image-20240806224456807

之前查的问题时存在某个Mysql8.0的Bug,Kill掉某个sql语句后,该sql语句实际还在运行,只能重启解决。但是由于是生产数据库。重启十分流程麻烦。进行两次维护重启后还是频繁告警,我在怀疑系统开发的sql语句到底写的是什么东西(只管查,不管耗时)。必须要和他们battle一番。要不最后还是我来背锅~

image-20240806230903579

最近一次执行时间超过30分钟的还是有70+条

image-20240806230502183

超长执行sql占用大量的数据库资源,如 CPU、内存和 I/O 带宽,导致其他并发的查询和操作响应变慢,甚至可能导致数据库死机。

今天就来和大家一起分析一下查询超长执行时间sql语句的方法和解决预防防控措施

1. 超长执行sql出现原因

数据量过大

  • 当处理大规模的数据表时,例如涉及数百万甚至数十亿条记录的查询,即使查询逻辑相对简单,也可能需要较长时间来处理和返回结果。

复杂的查询逻辑

  • 包含多层嵌套的子查询、多个表的连接操作、复杂的条件判断和聚合函数的组合使用。

    比如,一个查询同时涉及 5 个表的连接,每个表又有复杂的筛选条件,并且还包含多层子查询来获取相关的关联数据。

缺少合适的索引

  • 没有为经常用于查询、连接和排序的字段创建索引,导致数据库需要进行全表扫描来获取数据。

    例如,在一个经常根据用户 ID 进行查询的用户表中,如果没有为用户 ID 字段创建索引,每次查询都要遍历整个表。

服务器资源不足

  • 数据库服务器的硬件资源(如 CPU、内存、磁盘 I/O 性能)有限,无法快速处理复杂的查询请求。

    当服务器的内存不足时,可能会频繁进行磁盘交换,从而大大降低查询的执行速度。

网络延迟

  • 如果数据库服务器与应用程序服务器之间的网络连接不稳定或存在较高的延迟,数据传输时间会增加,导致 SQL 执行时间变长。

数据库配置不合理

  • 例如,缓存设置过小、连接池参数配置不当等。

    比如,缓冲池大小不足以容纳常用的数据,导致频繁的磁盘读取。

并发操作过多

  • 同时有大量的并发查询或更新操作,导致资源竞争和排队等待,从而延长单个 SQL 语句的执行时间。

下图为网络段子

你问我外包算什么东西?
我现在告诉你:
1:你们正编不敢连表查询,我们外包10张表都敢连

2:你们正编不敢在循环里查询数据库,我们外包敢

3:你们正编写代码考虑扩展性,我们外包直接写死

总之一句话正编做得了的,我们外包要做,正编做不了的我们外包更要做,够不够清楚

image-20240806231624529

3. sql 查询优化

正确的sql习惯可以在保证正确查询结果的前提下降低系统内存,IO的消耗,避免系统出现异常问题。

下面我将从可能导致数据库执行时间超长查询sql的情况来逐一分析并给出解决建议。

3.1 大表查询sql优化

对于数据量较大的sql语句(百万行及以上),万万不可不可直接select * ,执行时间很长不说,也很难找到我们需要的关键信息

以下是一个可能对千万级数据量的订单表进行全表扫描查询的示例 SQL 语句:

SELECT * FROM orders;

在这个示例中,* 表示选择所有列,orders 是订单表的表名。由于没有指定任何条件,这将导致对整个订单表进行全表扫描。

另一个示例是:

SELECT order_id, customer_name, total_amount FROM orders;

这个语句选择了 order_idcustomer_nametotal_amount 这几列,但同样没有添加任何筛选条件,仍然会进行全表扫描。

需要注意的是,在实际应用中,对如此大规模的数据量进行全表扫描通常是不推荐的,因为这可能会导致性能严重下降。应该尽量根据具体的业务需求添加合适的条件来缩小查询范围,例如:

SELECT * FROM orders WHERE order_date > '2024-08-01';

这个语句只会查询订单日期在 2024 年 8 月 1 日之后的订单,从而减少需要扫描的数据量,提高查询性能。

同样也可以限制查询结果数量

下面sql语句是从 orders 表中选取前 10 行的数据

SELECT * FROM orders BY order_id LIMIT limit 10

3.2 复杂查询逻辑sql优化

对于复杂查询逻辑sql,我们尽量分开查询,避免一次执行,这样虽然可能看似方便,实际执行时间太长,导致查询效率很低

部分优化方法如下

使用合适的索引

  • 分析查询中经常用于条件判断、连接和排序的字段,为这些字段创建合适的索引。

    例如,如果经常根据 order_date 字段进行查询,可以创建索引:CREATE INDEX idx_order_date ON orders (order_date);

分解复杂查询

  • 将一个复杂的大查询分解为多个较小的、更简单的查询,然后在应用程序层进行组合和处理。

    比如,原本一个包含多个子查询和连接的复杂查询,可以拆分为先获取一部分数据,然后基于这部分数据再进行后续的查询。

避免不必要的计算和函数

WHERE子句中尽量避免使用复杂的计算和函数,这可能会导致索引无法使用。

例如,不要写成 WHERE YEAR(order_date) = 2024 ,而是直接写成 WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01'

优化连接操作

  • 确保连接条件准确且高效,尽量使用主键或有索引的字段进行连接。

    比如,在连接两个表时,使用具有索引的 id 字段进行关联。

减少数据量

  • 在查询的早期阶段通过条件过滤掉尽可能多的数据,减少后续操作的数据量。

    先使用 WHERE 子句筛选出符合条件的记录,再进行其他操作。

使用临时表

  • 对于一些中间结果集,可以将其存储在临时表中,以提高查询的可读性和性能。

调整数据库配置参数

  • 根据服务器的硬件资源和业务需求,调整一些数据库的配置参数,如缓冲池大小、并发连接数等。

例如,有一个复杂的查询语句:

SELECT o.order_id, c.customer_name, SUM(o.order_amount) AS total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date BETWEEN '2024-01-01' AND '2024-08-06'
GROUP BY o.order_id, c.customer_name;

优化后的可能如下:

-- 先创建一个临时表存储筛选后的订单数据
CREATE TEMPORARY TABLE temp_orders AS
SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-08-06';-- 基于临时表进行连接和聚合操作
SELECT o.order_id, c.customer_name, SUM(o.order_amount) AS total_amount
FROM temp_orders o
JOIN customers c ON o.customer_id = c.customer_id
GROUP BY o.order_id, c.customer_name;

通过这样的优化,可以提高查询的性能和效率。

3.3 数据库配置优化

Mysql数据库常见配置文件名称如下

  1. /etc/mysql/my.cnf
  2. /etc/my.cnf
  3. /etc/mysql/mysqld.cnf
  4. /etc/mysql/conf.d/ (这里可能包含多个配置文件)
  5. /usr/local/mysql/etc/my.cnf(如果 MySQL 是通过源码编译安装的话)

在配置文件中修改下面的信息,附内核配置文件优化修改脚本

调整缓冲池大小(InnoDB Buffer Pool)

innodb_buffer_pool_size = 总内存的 50% - 80%

较大的缓冲池可以减少磁盘 I/O,加快数据访问速度。

增加并发线程数(Thread Concurrency)

thread_concurrency = CPU 核心数 * 2

这有助于提高并发处理能力。

优化查询缓存(Query Cache)

query_cache_type = 0  # 除非您的应用有大量相同的查询,否则建议关闭

调整连接参数

max_connections = 根据预期的并发连接数设置

优化 InnoDB 日志文件

innodb_log_file_size = 256M  # 根据写入量适当调整
innodb_log_buffer_size = 16M  # 缓冲日志数据

调整排序缓冲区大小(Sort Buffer Size)

sort_buffer_size = 2M  # 根据需要适当增大

调整读缓冲区大小(Read Buffer Size)

read_buffer_size = 2M  # 适当调整

启用并行查询(Parallel Query)

innodb_parallel_read_threads = 4  # 根据硬件配置调整

Mysql配置参数优化脚本

下面脚本可以保存后执行,但是请确认你的配置文件路径,仅供参考

#!/bin/bash# 备份原配置文件
# 这一步很重要,万一修改配置文件后出现问题,可以回滚到原始状态
cp /etc/my.cnf /etc/my.cnf.bak# 打开配置文件进行编辑
vi /etc/my.cnf# 添加或修改以下参数# [mysqld] 部分表示以下的参数是针对 mysqld 服务的
echo "[mysqld]" >> /etc/my.cnf# innodb_buffer_pool_size:InnoDB 缓冲池的大小,用于缓存表和索引数据。较大的值可以减少磁盘 I/O,提高性能。
# 这里设置为 512M,您可以根据服务器内存大小进行调整。
echo "innodb_buffer_pool_size = 512M" >> /etc/my.cnf# thread_concurrency:设置并发线程数,根据服务器的 CPU 核心数进行适当调整,以提高并发处理能力。
echo "thread_concurrency = 8" >> /etc/my.cnf# query_cache_type:查询缓存类型,设置为 0 表示关闭查询缓存。除非您的应用有大量重复的查询,否则关闭可能更好。
echo "query_cache_type = 0" >> /etc/my.cnf# max_connections:设置最大并发连接数,根据预期的并发连接需求进行设置。
echo "max_connections = 200" >> /etc/my.cnf# innodb_log_file_size:InnoDB 日志文件的大小,适当调整可以优化性能和恢复时间。
echo "innodb_log_file_size = 256M" >> /etc/my.cnf# innodb_log_buffer_size:InnoDB 日志缓冲区的大小,缓冲日志数据以减少磁盘写入次数。
echo "innodb_log_buffer_size = 16M" >> /etc/my.cnf# sort_buffer_size:排序缓冲区大小,用于排序操作,根据需要适当调整。
echo "sort_buffer_size = 2M" >> /etc/my.cnf# read_buffer_size:读缓冲区大小,用于顺序读取数据,适当调整。
echo "read_buffer_size = 2M" >> /etc/my.cnf# innodb_parallel_read_threads:InnoDB 并行读线程数,根据硬件配置调整,提高读取性能。
echo "innodb_parallel_read_threads = 4" >> /etc/my.cnf

4. 超长执行sql语句定位

下面我将介绍集中查询到底哪些sql语句在超时执行的语句,记录下来做针对性优化。

4.1 使用 SHOW PROCESSLIST 命令

SHOW PROCESSLIST;

这个命令会显示当前正在执行的所有连接和它们正在执行的 SQL 语句,以及执行的状态、时间等信息。您可以通过观察 Time 列来判断哪些语句执行时间较长。

image-20240807000702067

4.2.开启慢查询日志

首先,需要在 MySQL 的配置文件(通常是 my.cnfmy.ini)中进行相关设置:

slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2  # 单位为秒,设置超过多长时间的查询被认为是慢查询

然后,重启 MySQL 服务使配置生效。之后,执行时间超过设定阈值的 SQL 语句会被记录到指定的慢查询日志文件中。

4.3.利用性能分析工具

例如 pt-query-digest 工具,它可以对 MySQL 的查询日志(包括慢查询日志)进行分析,帮助您找出执行效率低下的 SQL 语句。

例如,如果您的慢查询日志文件名为 mysql-slow.log,可以使用以下命令进行分析:

pt-query-digest mysql-slow.log

4.4 查询近期长时间执行sql

下图可以查询24h内执行时间超过AVG_TIMER_WAIT的语句和相关执行用户

-- 从 performance_schema.events_statements_summary_by_digest 表中选择数据
SELECT * 
FROM performance_schema.events_statements_summary_by_digest 
-- 筛选条件:摘要文本不包含'performance_schema'
WHERE DIGEST_TEXT NOT LIKE '%performance_schema%' -- 平均等待时间大于1小时AND AVG_TIMER_WAIT > 3600000000000 -- 最后出现时间在过去 24 小时内AND LAST_SEEN >= DATE_SUB(NOW(), INTERVAL 24 HOUR) 
-- 按照平均等待时间降序排序
ORDER BY AVG_TIMER_WAIT DESC\G

5. 超长sql监控脚本

作为DBA,善于利用shell脚本和定时任务可以极大的减轻工作量,提高工作效率。

我们可以通过编写定时任务的方法每天执行时间较长的sql查询语句,获取其相关信息到txt文本中。

  1. 首先,创建一个包含上述查询语句的 SQL 脚本文件,例如 slow_query_check.sql ,内容如下:
SELECT * 
FROM performance_schema.events_statements_summary_by_digest 
WHERE DIGEST_TEXT NOT LIKE '%performance_schema%' AND AVG_TIMER_WAIT >3600000000000 AND LAST_SEEN >= DATE_SUB(NOW(), INTERVAL 24 HOUR) 
ORDER BY AVG_TIMER_WAIT DESC\G

image-20240807002258469

然后,使用 crontab -e 命令编辑定时任务。

在打开的文件中添加以下内容:

0 8 * * * 登录数据的命令,需要包含密码 < /home/mysql/zhangfakai/slow_query_check.sql > /home/mysql/zhangfakai/$(date +\%Y\%m\%d_slow_query_result.txt)

每天早上 8 点就会自动执行查询,并将结果输出到指定的 txt 文本中。

我们每天上班后可以先查询txt查看有无异常。

6. 总结

本文详细探讨了MySQL数据库中出现超时SQL语句的原因、定位方法、以及相应的优化和预防措施。通过深入分析,我们了解到MySQL数据库超时执行SQL的问题主要源于数据量过大、复杂的查询逻辑、缺少合适的索引、服务器资源不足、网络延迟、数据库配置不合理以及并发操作过多等多方面因素。

针对这些问题,本文提出了多项优化策略。在SQL查询优化方面,强调了避免大表全表扫描、优化复杂查询逻辑、使用合适的索引、分解复杂查询、避免不必要的计算和函数、优化连接操作、减少数据量以及使用临时表等技巧。同时,也介绍了如何通过调整数据库配置参数(如缓冲池大小、并发线程数、查询缓存、连接参数等)来优化数据库性能。

在超时SQL语句的定位方面,本文介绍了使用SHOW PROCESSLIST命令、开启慢查询日志、利用性能分析工具(如pt-query-digest)以及查询近期长时间执行的SQL语句等多种方法。这些方法有助于快速定位问题SQL语句,从而进行针对性的优化。

最后,本文还提出了编写超长SQL监控脚本的建议,通过定时任务自动检测长时间执行的SQL语句,并生成报告,帮助DBA及时发现问题并进行处理。

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

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

相关文章

登录页滑块验证图

效果图 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head> <b…

【Kubernetes】k8s集群中pod的容器资源限制和三种探针

目录 一.关于pod容器的资源限制 1.资源限制的单位 1.1.CPU 资源单位 1.2.内存 资源单位 二.关于QOS服务质量&#xff08;pod的调度和驱逐有限制&#xff09; 1.QoS服务质量分类 2.驱逐顺序 三.关于pod容器的三种探针 1.探针的三种规则 2.Probe支持三种检查方法 3.探…

docker安装及使用

一、docker优点及作用 优点&#xff1a; 基础镜像MB级别创建简单隔离性强启动速度秒级移植与分享放便 作用&#xff1a;资源隔离 cpu、memory资源隔离与限制访问设备隔离与限制网络隔离与限制用户、用户组隔离限制 二、docker安装 2.1.配置yum源 yum install -y yum-uti…

Mysql开启SSL

等二测出未开启SSL,如下 have_openssl、have_ssl都是DISABLED也不知道当时为啥没开&#xff0c;看最近的都是开启的,整改必去得开了&#xff0c;开启步骤 1.生成秘钥 进入mysql的bin目录下&#xff0c;运行 ./mysql_ssl_rsa_setup运行后会生成证书 默认证书会在mysql的data…

主从备份(复制)

一、备份的三种类型 备份的三种主要类型包括热备份、逻辑备份和物理备份&#xff0c;每种备份类型都有其特定的应用场景和优缺点。 1. 热备份 定义&#xff1a; 热备份是在数据库或系统处于正常运行状态下进行的备份。这种备份方式允许在不停机的情况下对数据库或系统数据进…

【Python】Django Web 框架

一、常用的Web开发框架 1.Django Django是一个由Python写成的开放源代码的Web应用框架。这套框架的主要目标是使开发复杂、数据库驱动的网站变得简单。Django注重组件的重用性和“可拔插性”、敏捷开发和DRY(Dont Repeat Yourself)法则 2.Flask Flask是一个微型的Python开发…

反序列化靶机实战serial(保姆级教程)

一.信息收集 靶机地址下载&#xff1a;https://download.vulnhub.com/serial/serial.zip 打开靶机&#xff0c;在kali虚拟机中进行主机存活探测 可以知道靶机ip地址为192.168.133.171 然后扫描端口 可以发现有一个22端口跟80端口 然后接下来用kali扫描它的目录 可以发现有一…

Django-Oscar开发独立站/外贸商城教程与问题记录

​特别说明&#xff1a; 本博客为个人开发Django-Oscar时的经验总结&#xff0c;方便后期维护&#xff01;&#xff08;第一次这么认真的记录这种大型项目&#xff0c;打个广告吧&#xff1a;本人可接单算法程序开发&#xff0c;包含深度学习和图像相关……等相关&#xff09;…

Unity补完计划 之 音效

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 首先&#xff0c;音频这块组件较少&#xff0c;但是内容很重要&#xff0c;因为对于任何一款非特殊面向人群的游戏来说&a…

STM32入门三(开漏输出点亮外接的LED)

前面2章用的是推免输出&#xff0c; 推免输出: 输出端由两个晶体管构成&#xff1a;一个N沟道晶体管和一个P沟道晶体管。这两个晶体管一般不会同时导通&#xff0c;避免短路; 白话&#xff0c;就是输入高还是低&#xff0c;由你的GPIO 控制&#xff08;GPIO 输出高就高&#xf…

【LeetCode 1991 找到数组的中间位置 / LeetCode 724 寻找数组的中心下标】中间索引问题

1991 题目描述 暴力解法1&#xff1a; 思路&#xff1a; 遍历下标&#xff0c;求出左边和和右边和比较两边是否相等相等直接返回值没有符合的返回 -1 class Solution {public int findMiddleIndex(int[] nums) {int lennums.length;//初始化一个变量 midIndex 为 -1&#xff…

C# Unity 面向对象补全计划 七大原则 之 接口隔离原则 (ISP) 难度:☆ 总结:大接口分成小的,然后该干啥干啥

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 请看专栏&#xff1a;http://t.csdnimg.cn/mIitr&#xff0c;查漏补缺 1.接口隔离原则 (ISP) 这…

MySQL--查询数据

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、基本查询语句 MySQL从数据表中查询数据的基本语句为SELECT语句。其基本格式为&#xff1a; select {* | <字段列表>}[from <表1>,&l…

贝壳找房:基于OceanBase构建实时字典服务的实践 | OceanBase案例

贝壳找房作为领先的居住服务综合平台&#xff0c;一直在推进居住产业的数字化与智能化升级。该平台通过汇聚并赋能优质的服务者&#xff0c;旨在为中国广大家庭带来涵盖二手房买卖、新房交易、房屋租赁、家装、家居以及家庭服务等全方位、高质量且高效的居住服务体验。 在贝壳…

0803实操-数字取证

0803实操-数字取证 易失性数据收集 创建应急工具箱&#xff0c;并生成工具箱校验和&#xff0c;能在最低限度地改变系统状态的情况下收集易失性数据。 数据箱 使用md5sums.exe对工具目录中的所有文件进行计算 获取计算机本地日期和时间。输入命令date/t>timefront.txt和…

鸿蒙图形开发【3D引擎接口示例】

介绍 本实例主要介绍3D引擎提供的接口功能。提供了ohos.graphics.scene中接口的功能演示。 3D引擎渲染的画面会被显示在Component3D这一控件中。点击按钮触发不同的功能&#xff0c;用户可以观察渲染画面的改变。 效果预览 使用说明 在主界面&#xff0c;可以点击按钮进入不…

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——4Bin模型转化过程

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——4Bin模型转化过程 ​ 大家好&#xff0c;经过前几期的介绍&#xff0c;对于X3派上的Yolo模型部署&#xff0c;我们已经可以进行到最后一步了 ​ 今天给大家带来&#xff0c;转模型的关键步骤&#xff0…

学习进行到了第十七天(2024.8.5)

1.Mybatis的定义 数据持久化是将内存中的数据模型转换为存储模型&#xff0c;以及将存储模型转换为内存中数据模型的统称。例如&#xff0c;文件的存储、数据的读取以及对数据表的增删改查等都是数据持久化操作。MyBatis 支持定制化 SQL、存储过程以及高级映射&#xff0c;可以…

linux磁盘可视化分析工具

在 Linux 系统中&#xff0c;了解磁盘使用情况对于系统维护和优化至关重要。文件和目录随着时间的推移会占据大量磁盘空间&#xff0c;了解哪些部分占用的空间最多可以帮助我们更好地管理和清理磁盘。Baobab&#xff0c;也称为 GNOME Disk Usage Analyzer&#xff0c;是一款非常…

Radamsa:一款高性能通用模糊测试工具

关于Radamsa Radamsa是一款高性能的通用模糊测试工具&#xff0c;广大研究人员可以将其当作一个应用程序稳定性测试的测试用例生成工具。 工具运行机制 该工具使用简单&#xff0c;支持自定义脚本开发&#xff0c;可以用于测试程序对格式错误和潜在恶意输入的承受能力。它的工…