MySQL训练营-慢查询诊断问题

slow_query_log + long_query_time

slow_query_log:日志开关,是否记慢查询日志

long_query_time:超过多长时间判定为慢查询

查看参数设置:

  • SHOW VARIABLES LIKE ‘slow_query_log’;
  • SHOW VARIABLES LIKE ‘long_query_time’;

实践建议:

  1. set global long_query_time=1;
  2. 分析型业务,set long_query_time=N;

全局设置为1,session级别针对耗时的分析型业务可以设置时间更长一点。

生成并查看一条慢查询日志:

先将slow_query_log开关打开:set global slow_query_log= on;,只能使用global级别。

再将long_query_time时间设置为1s:set global long_query_time= 1;set long_query_time= 1;都行。

在终端中执行select sleep(10);slow_query.log文件可以看到:

/usr/sbin/mysqld, Version: 8.0.18 (MySQL Community Server - GPL). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
# Time: 2024-12-22T03:32:41.457742Z
# User@Host: root[root] @ localhost [127.0.0.1]  Id:    10
# Query_time: 10.000678  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 1
SET timestamp=1734838351;
select sleep(10);
  • Query_time: 10.000678

    表示整个查询从开始执行到执行完毕所花费的总时间,单位是秒。在这个例子中,查询总共耗时 10.000678 秒。

  • Lock_time: 0.000000

    指的是该查询在获取锁资源上所花费的时间,单位同样是秒。这里显示为 0 秒,意味着这个查询在执行过程中基本没有因为等待获取锁而耗费时间,即没有遇到锁等待的情况,能直接获取到所需的锁进行后续的操作。

  • Rows_sent: 1

    代表查询最终返回给客户端的行数。此例中返回了 1 行数据给客户端,说明查询结果的数据量比较小,不过查询耗时却很长,这就提示可能是查询执行过程中的其他环节(比如函数执行等情况)导致了整体的缓慢,而非数据量太大需要大量传输的原因。

  • Rows_examined: 1

    表示查询执行过程中数据库引擎扫描的数据行数。这里扫描了 1 行,结合返回行数等情况可以分析出数据库在执行该查询时的数据访问规模。

log_slow_extra

在MySQL中,log_slow_extra是一个与慢查询日志(Slow Query Log)相关的参数。它用于控制在慢查询日志中是否记录额外的信息。这些额外信息可以帮助数据库管理员(DBA)更深入地了解查询性能问题的原因。

同样的可以查看参数设置:

  • SHOW VARIABLES LIKE ‘log_slow_extra’;

实践建议:

打开参数后,CPU、内存、磁盘占用会比更多。但是可以提供更多的定位信息,建议稳定后打开。

5.7 和 8.0 关于慢查询日志差异

前值准备(建表准备数据):

drop table if exists t;

CREATE TABLE t (
    id INT PRIMARY KEY AUTO_INCREMENT,
    c INT
);

INSERT INTO t (c) VALUES (0), (0);

场景:

session1session2
begin;
update t set c=1 where id=1;
update t set c=2 where id=1;
//blocked
select sleep(10);
commit;
//updated,affected rows=1

问:session2是否记录慢查询?

老师课上给的答案:5.7不会记,MySql会扣除行锁时间。8.0会记录。(答案存疑)

先使用mysql:8.0.18进行测试,慢查询日志中只有执行sleep(10)的记录:

怀疑是mysql的问题,再使用mysql:8.0.40进行测试,能复现该场景:

可见是mysql:8.0.x某个小版本引入的新特性,非mysql:8.0版本都有的。

样例分析(MySQL 8.0)

session1session2session3
lock table t write
begin;
update t set c=c+1 where id=1;
begin;
update t set c=c*10 where id=1;
unlock table;
commit;

解锁后,先执行session1再执行session3session1先获取到锁应该是,等待时间比session3长。

慢日志:

# Time: 2024-12-25T13:43:04.675707Z
# User@Host: root[root] @ localhost []  Id:     9
# Query_time: 37.684517  Lock_time: 0.000004 Rows_sent: 0  Rows_examined: 1
SET timestamp=1735134146;
update t set c=c+1 where id=1;
# Time: 2024-12-25T13:43:19.938977Z
# User@Host: root[root] @ localhost []  Id:    13
# Query_time: 43.321374  Lock_time: 15.263238 Rows_sent: 0  Rows_examined: 1
SET timestamp=1735134156;
update t set c=c*10 where id=1;

可知Lock_time中只记录了行锁的等待时间。Query_time-Lock_time不仅包括SQL语句的执行时间,还包括等待表锁的时间。

log_queries_not_using_indexes

log_queries_not_using_indexes是 MySQL 中的一个参数。当这个参数设置为ON时,MySQL 会将没有使用索引的查询语句记录到慢查询日志(slow query log)中。

前置准备:

drop table if exists t;

CREATE TABLE t(
    id int NOT NULL,
    c int DEFAULT NULL,
    d int DEFAULT NULL,
    e int DEFAULT NULL,
    PRIMARY KEY(id ),
    KEY c(c),
    KEY d(d)
);

insert into t values(1,833,10,1),(2,2,2,2),(3,3,3,3);

练习:update t set e=e*10 where e = 2;锁多少行?

答案锁全表,可以在一个实物中更新update t set e=e*10 where e = 2;,另一个事物执行update t set e=e*10 where e = 1;可以看到在等待:

session1session2
begin;
update t set e=e*10 where e = 1;
update t set e=e*10 where id = 2;

在默认隔离级别(可重复读)下,会阻塞锁全表。在读提交下,不会阻塞。

可以查看:https://tech.meituan.com/2014/08/20/innodb-lock.html,了解锁释放的实际。

通过刚刚的例子,可以看到没有走索引的语句会存在潜在的风险,所以这个参数建议打开。

那么,参数打开后导致慢查询日志过多,如以下对系统表的查询也会记录慢日志:

select * from information_schema.processlist;
select * from information_schema.innodb_trx;
show engine innodb status\G # 实测不会记

解决办法:

  1. log_queries_not_using_indexes+log_throttle_queries_not_using_indexes
    log_throttle_queries_not_using_indexes:限制每分钟无主键语句的记录条数上限。容易误伤需要记录的慢查询日志。
  2. log_queries_not_using_indexes+min_examined_row_limit
    min_examined_row_limit:扫描行数少于这个值的语句,不记入慢查询日志。

方案2,是否可行?先分析select count(*) from t;在8.0.17版本以前是3,新版本为0。新版本优化为由存储层计算结果直接返回给SQL层。

# Time: 2024-12-25T14:15:46.264553Z
# User@Host: root[root] @ localhost []  Id:    12
# Query_time: 40.595383  Lock_time: 0.000006 Rows_sent: 1  Rows_examined: 0
SET timestamp=1735136105;
select count(*) from t;

所以方案2会导致,该语句不记录。此外在以下场景:

先创建表与存储过程:

drop table if exists t;

CREATE TABLE t (
    id INT,
    c INT
);

INSERT INTO t (id, c) VALUES (0,0), (1,0), (2,0), (3,0), (4,0);

//准备一个存储过程,对id=3这一行做5万次更新
delimiter ;;
create procedure udata3() begin
declare i int; set i=1; while(i<=50000) do
    update t set c=c+1 where id=3;
    set i=i+1;
end while;
end;;
delimiter ;

再进行以下操作:

session1(隔离级别RR)session2
begin;
select * from t where id = 1;
call udata3();
select * from t where id = 3; // 查询Q

可以在 MySQL 客户端连接到数据库后,使用SET语句来设置当前会话的事务隔离级别为 RR,示例代码如下:

-- 设置当前会话的事务隔离级别为RR
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 开始事务
START TRANSACTION;
-- 这里编写事务中的SQL语句,例如查询、插入、更新等操作
SELECT * FROM your_table;
-- 提交事务
COMMIT;
  1. 查询Q的row_examined是多少?

为1,存储层最会返回最新的一行数据

  1. 查询Q的的查询时间更接近那个数值?

A:0.01s B:1.01s

答案是B,现在数据库都实现了MVCC会保留历史版本,为了找到最新的数据会从最新的版本遍历找到最老的版本(可重复读隔离级别)。

测试结果:

# Time: 2025-01-08T12:28:58.505518Z
# User@Host: root[root] @ localhost []  Id:    15
# Query_time: 0.000387  Lock_time: 0.000004 Rows_sent: 1  Rows_examined: 5
SET timestamp=1736339338;
select * from t where id = 1;

# Time: 2025-01-08T12:32:38.671135Z
# User@Host: root[root] @ localhost []  Id:    16
# Query_time: 209.297586  Lock_time: 0.000000 Rows_sent: 0  Rows_examined: 250000
SET timestamp=1736339558;
call udata3();

# Time: 2025-01-08T12:33:16.075252Z
# User@Host: root[root] @ localhost []  Id:    15
# Query_time: 0.058057  Lock_time: 0.000004 Rows_sent: 1  Rows_examined: 5
SET timestamp=1736339596;
select * from t where id = 3;

可以看到执行查询时间虽然没有1s那么夸张,但是也用了0.058s。也比执行存储过程前的0.0003慢了很多。这种情况也应该记录慢查询日志,但是因为min_examined_row_limit的配置可能不记录日志。

生产建议:min_examined_row_limit不应该在生产环境上设置。

内核改进思路(Mysql官方不提供):

  1. set global log_queries_not_using_indexes_white_user = ‘xxx’ (模拟)

白名单管理,将监控相关的用户查询屏蔽。

  1. 改为 global,session 变量

set global log_queries_not_using_indexes=on 监控应用端:

set log_queries_not_using_indexes=off(模拟)

生产建议:根据业务情况可以先不开,稳定后打开。

慢查询影响性能嘛?

慢查询日志影响性能吗?

A. 影响 B. 不影响

A

执行错误的语句记不记入慢查询日志?

A. 记录 B. 不记录

A

如何验证?

锁等待,A线程开启事务,更新一行。B线程更新同一行,会报错。验证结果:

# Time: 2025-01-08T13:01:37.382271Z
# User@Host: root[root] @ localhost []  Id:    15
# Query_time: 0.000530  Lock_time: 0.000004 Rows_sent: 0  Rows_examined: 5
SET timestamp=1736341297;
update t set c=c+1 where id=3;
# Time: 2025-01-08T13:02:30.110640Z
# User@Host: root[root] @ localhost []  Id:    16
# Query_time: 50.019117  Lock_time: 50.018677 Rows_sent: 0  Rows_examined: 0
SET timestamp=1736341300;
update t set c=c+1 where id=3;

慢查询日志是在语句执行的哪个阶段写入的?

A. 语句执行开始阶段 B. 语句执行结束,发查询结果给客户端前 C. 语句执行结束,发查询结果给客户端后

C

可以使用下面方法测试:

gdb -p <pid of mysqld>
(gdb) b my_error
(gdb) c
root@devops_db 15:07: [test]> select a;

看此时slow log还没有输出 select a 这个语句

结论:slowlog 是在语句结果返回给客户端后再输出的

疑问:那为什么开slow log会影响性能?

因为在记录慢日志时,线程无法处理新来的请求。

怎么减少突发慢查询对系统的影响

  1. 提前发现慢查询

业务回归测试时提前发现。测试环境中使用:set global long_query_time = 0;set global log_slow_extra = on;

  1. 审计日志采集

  2. 分析和预警

怎么判断慢查询语句是否有优化空间?

对比执行过程的消耗,跟输出结果。如创建表并插入数据:

drop table if exists a;

create table a(id int primary key AUTO_INCREMENT, c int , d int,e text, index(c))engine=innodb;

DROP PROCEDURE IF EXISTS insert_data;

-- 创建存储过程
DELIMITER //
CREATE PROCEDURE insert_data()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i <= 100 DO
        INSERT INTO a ( c, d, e)
        SELECT  i, i, REPEAT('a', 16000);
        SET i = i + 1;
    END WHILE;
END //
DELIMITER ;

-- 调用存储过程来执行插入操作
CALL insert_data();
  • select * from a;

    表本身很大,没有优化空间

  • select * from a where c>10 and c<20 and d>=15;

读了9行,但是只返回了5行。

# User@Host: root[root] @ localhost []  Id:    34
# Query_time: 0.000679  Lock_time: 0.000006 Rows_sent: 5  Rows_examined: 9
SET timestamp=1737638707;
select * from a where c>10 and c<20 and d>=15;

优化语句:

select * from a where id in (select id from a where c>10 and c<20 and d>=15);

慢查询日志:

# Time: 2025-01-23T13:25:41.458971Z
# User@Host: root[root] @ localhost []  Id:    34
# Query_time: 0.000880  Lock_time: 0.000004 Rows_sent: 5  Rows_examined: 14
SET timestamp=1737638741;
select * from a where id in (select id from a where c>10 and c<20 and d>=15);

理论分析,因为e字段笔记大,这里用到了mysql的行外存储(https://www.cnblogs.com/better-farther-world2099/articles/14717436.html),所以第一个语句返回的是9行完整的数据行,再进行d字段的过滤。而第二个语句返回的是9个不完整的的数据行,然后再回表获取5个完整的数据行。

测试结果与实际测试结果不一致,应该是当前数据行的大小还不够大。理论分析是成立的。建立c和d的联合索引应该是更好的,存储层只会给sql层返回5行完整数据。

课堂练习

题目1

RR隔离级别下,表t的建表结构和初始化数据如下:

create table t(id int primary key,c int)engine=innodb;
insert into t values(1,1),(11,11),(21,21);

在会话1 执行如下语句:

begin;
select * from t lock in share mode;

那么,会话2的以下哪些语句会被进入“等待行锁”的状态?

A: insert into t values(15,15);

B: update t set c=c+1 where id=15;

C: delete from t where id=15;

D: alter table t add d int;

A

A会被锁住,RR隔离级别要保证可重复读,会加间隙锁

B、C不会,没有相关行,不会锁任何行

D也不会,因为D需要的是表结构锁。

题目2

表t1使用InnoDB引擎,以下哪个场景会导致语句Q1: select * from t1 limit 1 被堵住?

A:另一个线程在Q1执行之前,执行了 alter table t1 add index(f1),当前处于“拷贝数据到临时表”阶段

B:另一个线程在Q1执行之前,执行了 truncate table t1,当前处于waiting for metadata lock阶段

C:另一个线程在Q1执行之前,执行了 delete from t1,且未执行完成

D:另一个线程在Q1执行之前,执行了 lock table t1 write,并执行完成

A:Mysql实现在线加索引

B:

MDL机制简介

MDL是 MySQL 为了保证数据定义语言(DDL)和数据操纵语言(DML)操作之间的数据一致性而引入的一种锁机制。当一个事务对表执行 DDL 操作(如 TRUNCATE TABLE)时,会获取该表的元数据写锁;而当执行DML操作(如SELECT)时,会获取该表的元数据读锁。

具体阻塞原因

TRUNCATE TABLE 操作:TRUNCATE TABLE 是一个 DDL 操作,执行时会获取表 t1 的元数据写锁。元数据写锁是排他锁,意味着在持有该锁期间,其他事务无法获取该表的任何元数据锁(包括读锁和写锁)。
SELECT 操作:SELECT * FROM t1 LIMIT 1 是一个 DML 操作,执行时需要获取表 t1 的元数据读锁。但由于之前的 TRUNCATE TABLE 操作已经持有了元数据写锁,所以 SELECT 操作无法获取到元数据读锁,只能进入等待状态,即 waiting for metadata lock。

C:不影响Q1的第一行数据的读取

D:也会阻塞,因为加的是表的排他锁。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2025年最新汽车零部件企业销售项目管理解决方案

在汽车零部件企业&#xff0c;销售项目管理的不规范和销售预测的不准确性常导致生产计划无法及时调整&#xff0c;因此客户关系常常中断&#xff0c;导致企业业务机会的丧失。为解决该问题&#xff0c;企业需要投入更多资源以优化销售流程与销售预测。 1、360多维立体客户视图…

K8S中ingress详解

Ingress介绍 Kubernetes 集群中&#xff0c;服务&#xff08;Service&#xff09;是一种抽象&#xff0c;它定义了一种访问 Pod 的方式&#xff0c;无论这些 Pod 如何变化&#xff0c;服务都保持不变。服务可以被映射到一个静态的 IP 地址&#xff08;ClusterIP&#xff09;、一…

大模型:LangChain技术讲解

一、什么是LangChain 1、介绍 LangChain是一个用于开发由大型语言模型提供支持的Python框架。它提供了一系列工具和组件&#xff0c;帮助我们将语言模型集成到自己的应用程序中。 有了它之后&#xff0c;我们可以更轻松地实现对话系统、文本生成、文本分类、问答系统等功能。…

【优选算法篇】2----复写零

---------------------------------------begin--------------------------------------- 这道算法题相对于移动零&#xff0c;就上了一点点强度咯&#xff0c;不过还是很容易理解的啦~ 题目解析&#xff1a; 这道题如果没理解好题目&#xff0c;是很难的&#xff0c;但理解题…

office 2019 关闭word窗口后卡死未响应

最近关闭word文件总是出现卡死未响应的状态&#xff0c;必须从任务管理器才能杀掉word 进程&#xff0c;然后重新打开word再保存&#xff0c;很是麻烦。&#xff08;#其他特征&#xff0c;在word中打字会特别变慢&#xff0c;敲击键盘半秒才出现字符。&#xff09; office官网…

acm培训 part 1(学习总结)

第一部分的重点为语法糖&#xff0c;时空复杂度&#xff0c;stl容器等等&#xff0c;下面就简单介绍一下这些部分。 1. 语法糖 1.1 定义 语法糖是由英国计算机科学家彼得约翰兰达提出的一个术语&#xff0c;指的是编程语言中添加的某种语法&#xff0c;这种语法对语言的功能…

Arduino基础入门学习——OLED显示屏+DHT11采集温湿度并显示

Arduino基础入门学习——OLED显示屏DHT11显示温湿度 一、前言二、准备工作三、程序代码四、结束语 一、前言 本篇文章主要使用OLED液晶显示屏模块和DHT11温湿度传感器&#xff0c;获取环境温湿度并显示在显示屏&#xff0c;也算是结合之前我所编写的博客给大家带来一个算是比较…

Kubernetes相关知识入门详解

一、Pod的滚动升级 1.服务升级的一般思路&#xff1a;停止与该服务相关的所有服务pod&#xff0c;重新拉去更新后的镜像并启动。这种方法存在一个比较现实的问题是逐步升级导致较长时间的服务不可用。 2.Kubernetes滚动升级的思路&#xff1a;通过滚动升级的命令创建新的rc&…

云原生时代,如何构建高效分布式监控系统

文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目&#xff0c;由于其良好的架构设计和完善的生态&#xff0c;迅速成为了监控…

Qt 5.14.2 学习记录 —— 십구 事件

文章目录 1、事件的概念2、处理事件3、鼠标事件1、鼠标单击和双击2、鼠标移动3、鼠标滚轮滚动 4、键盘事件5、定时器事件6、窗口移动和大小改变事件 1、事件的概念 用户进行操作时会产生事件&#xff0c;事件可以关联处理函数。Qt封装了操作系统的事件机制&#xff0c;然后进一…

10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析

10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析 文章目录 10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析1. 规则持久化1.1 Nacos Server 配置中心-规则持久化实例 2. 最后&#xff1a; 1. 规则持久化 规则没有持久化的问题 如果 sentinel 流控规则没有…

地学专业想提前准备春招?怎么准备自己的简历?

眼看着即将过年&#xff0c;过完年后基本上春招也要开始提上日程 之前咱们说过&#xff0c;很多同学认为自身技术过硬就会一路顺风&#xff0c;自己经验丰富、编程技术过硬&#xff0c;就不愁找不到工作&#xff0c;这固然是取得好offer的基础。 但再好的技术也不可能通过混乱…

IoTDB结合Mybatis使用示例(增删查改自定义sql等)

IoTDB时序库是当前越来越流行以及基于其优势各大厂商越来越易接受的国产开源时序数据库&#xff0c;针对IoTDB的内容不做过多介绍&#xff0c;在使用该时序库时&#xff0c;往往有一定入门门槛&#xff0c;不同于关系型数据库或文档型数据库那般方便维护和接入开发&#xff0c;…

Go语言的栈空间管理

Go 语言的栈空间管理 Go 语言的栈空间管理是其并发模型的核心之一。Go 的运行时环境&#xff08;runtime&#xff09;采用动态栈分配机制&#xff0c;能够根据 Goroutine 的需求动态扩展和收缩栈空间&#xff0c;避免了传统固定栈大小的限制。Go 的栈管理经历了从 分块式栈 到…

细说STM32F407单片机电源低功耗StandbyMode待机模式及应用示例

目录 一、待机模式基础知识 1、进入待机模式 2、待机模式的状态 3、退出待机模式 二、待机模式应用示例 1、示例功能和CubeMX项目设置 &#xff08;1&#xff09; 时钟 &#xff08;2&#xff09; DEBUG、LED1、KeyRight、USART6、CodeGenerator &#xff08;3&#x…

我谈《概率论与数理统计》的知识体系

学习《概率论与数理统计》二十多年后&#xff0c;在廖老师的指导下&#xff0c;才厘清了各章之间的关系。首先&#xff0c;这是两个学科综合的一门课程&#xff0c;这一门课程中还有术语冲突的问题。这一门课程一条线两个分支&#xff0c;脉络很清晰。 概率论与统计学 概率论…

第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

第十五届的题目在规定时间内做出了前5道&#xff0c;还有2道找时间再磨一磨。现在把做的一些思路总结如下&#xff1a; 题1&#xff1a;握手问题 问题描述 小蓝组织了一场算法交流会议&#xff0c;总共有 50人参加了本次会议。在会议上&#xff0c;大家进行了握手交流。按照惯例…

OpenEuler学习笔记(四):OpenEuler与CentOS的区别在那里?

OpenEuler与CentOS的对比 一、基本信息 起源与背景&#xff1a; OpenEuler&#xff1a;由华为发起&#xff0c;后捐赠给开放原子开源基金会&#xff0c;旨在构建一个开放、多元化的云计算和边缘计算平台&#xff0c;以满足华为及其他企业的硬件和软件需求。CentOS&#xff1a;…

【MySQL — 数据库增删改查操作】深入解析MySQL的create insert 操作

数据库CRUD操作 1 CRUD简介 CURD是对数据库中的记录进行基本的增删改查操作: 2. Create 新增 语法 INSERT [INTO] table_name[(column [&#xff0c;column] ...)] VALUES(value_list)[&#xff0c;(value_list)] ... # value 后面的列的个数和类型&#xff0c;要和表结构匹配…

苍穹外卖—订单模块

该模块分为地址表的增删改查、用户下单、订单支付三个部分。 第一部分地址表的增删改查无非就是对于单表的增删改查&#xff0c;较基础&#xff0c;因此直接导入代码。 地址表 一个用户可以有多个地址&#xff0c;同时有一个地址为默认地址。用户还可为地址添加例如&q…