第十九章 为什么我只查一行的语句,也执行这么慢?

2024-01-03 16:48

本文主要是介绍第十九章 为什么我只查一行的语句,也执行这么慢?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第十九章 为什么我只查一行的语句,也执行这么慢?

查询长时间不返回

一条查询语句始终无返回,可能是因为什么原因导致的 ?

  • 可能在等待 MDL 锁 释放
    • 查询语句执行时申请的是 MDL 读锁,若之前有 MDL 写锁 处于申请中或正持有中,则MDL 读锁 等待
  • 可能在等待 flush 锁(在第六章讲过 flush tables with read lock 会加全局读锁)
    • 执行 flush statement 类语句可能发生锁等待,其中:
      • flush tables with read lock:会关闭所有打开的表并给所有的表在库层级添加一个全局的读锁
      • flush tables with read lock:不会被其他会话的事务阻塞。例如开启一个会话事务,更新,然后直接执行本会话 flush,此时再执行上一个会话事务的提交,提交由于 flush 进入了阻塞,在等待 flush 被unlock 之后,该事务的提交继续执行。(想要复现 flush tables with read lock 被阻塞的场景,可以让 select sleep(60) from t 来进行 —— 原理是持续不断地打开表对象)
      • flush table t with read lock:会首先获取 t 表的MDL写锁,因此它要首先等待所有打开 t 表的事务完成,然后才从表缓存中对表进行刷新,重新打开表,并获取表锁,随后将 MDL 写锁降级为 MDL 读锁。在获得表锁并进行 MDL 写锁降级后,其他连接可以读取该表,但不能更新表(DML、DDL)
      • flush table t with read lock:反而会被对应表的其他事务给阻塞到
  • 可能在等待行锁
    • 如果查询的语句加了读锁 —— lock in share mode,那当 读取的数据有写锁占用时,查询线程将被阻塞
      • lock in share mode:是要求当前读,也就是要读取最新的数据
      • 不加锁就是 一致性读,最开始读到什么,即使中间有人更新了,也读的是旧值

怎么排查查询语句很久没有反馈的情况 ? 讲一下你的步骤流程 ?

-- 查看当前库的所有线程
show processlist;
  • 此外,还可以通过 performance_schema 库 和 sys 库 来排查
show variables like '%performance_schema%';
set performance_schema = 'ON';
-- 开启此功能,会有10%的性能开销
  • 随后,执行
select * from performance_schema.setup_instruments where name='wait/lock/metadata/sql/mdl';
-- 若结果两者非YES,需设置YES,才可继续UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' where name='wait/lock/metadata/sql/mdl';
  • 那么,当出现查询线程被阻塞时,可以在其他会话执行
SELECT * from sys.schema_table_lock_waits;
SELECT blocking_pid from sys.schema_table_lock_waits;
  • 即可查出当前持有锁的线程

Untitled

  • 建议销毁线程时,执行 kill X 而非 kill query X
  • 因为当线程正在执行的语句非查询语句时,后者是无效的方法

数据量极少但查询很慢

什么情况下,数据量极少,但查询却很慢呢 ?

  • 热点更新语句,其在 MVCC 控制下,当前事务与最新数据版本间的回滚段过长时,查询会很慢
  • 一般直接加读锁(会进行当前读)进行验证当前数据与事务一致性视图下的数据差异
  • 例如下面这个语句:
select * from t where id=1select * from t where id=1 lock in share mode

Untitled

Untitled

这篇关于第十九章 为什么我只查一行的语句,也执行这么慢?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/566389

相关文章

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

python之流程控制语句match-case详解

《python之流程控制语句match-case详解》:本文主要介绍python之流程控制语句match-case使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录match-case 语法详解与实战一、基础值匹配(类似 switch-case)二、数据结构解构匹

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程