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

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

相关文章

Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤

《MybatisPlusJSqlParser解析sql语句及JSqlParser安装步骤》JSqlParser是一个用于解析SQL语句的Java库,它可以将SQL语句解析为一个Java对象树,允许... 目录【一】jsqlParser 是什么【二】JSqlParser 的安装步骤【三】使用场景【1】sql语

sql语句字段截取方法

《sql语句字段截取方法》在MySQL中,使用SUBSTRING函数可以实现字段截取,下面给大家分享sql语句字段截取方法,感兴趣的朋友一起看看吧... 目录sql语句字段截取sql 截取表中指定字段sql语句字段截取1、在mysql中,使用SUBSTRING函数可以实现字段截取。例如,要截取一个字符串字

MySQL中SQL的执行顺序详解

《MySQL中SQL的执行顺序详解》:本文主要介绍MySQL中SQL的执行顺序,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql中SQL的执行顺序SQL执行顺序MySQL的执行顺序SELECT语句定义SELECT语句执行顺序总结MySQL中SQL的执行顺序

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分

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