MySQL查询执行(四):查一行也很慢
假设存在表t,这个表有两个字段id和c,并且我在里面插入了10万行记录。
-- 创建表t
CREATE TABLE `t` (`id` int(11) NOT NULL,`c` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB;-- 通过存储过程向t写入10w行数据
delimiter ;;
create procedure idata()
begindeclare i int;set i=1;while(i<=100000)doinsert into t values(i,i);set i=i+1;end while;
end;;
delimiter ;-- 插入数据
call idata();
查询长时间不返回
查询长时间不返回的原因:被其他线程堵住了。
在表t执行下面的SQL语句:
select * from t where id = 1;
查询结果长时间不返回。
一般碰到这种情况的话, 大概率是表t被锁住了。 接下来分析原因的时候, 一般都是首先执行一下show processlist命令, 看看当前语句处于什么状态。
然后我们再针对每种状态, 去分析它们产生的原因、 如何复现, 以及如何处理。
场景一:等MDL锁
如图所示, 就是使用show processlist命令查看Waiting for table metadata lock的示意图。
出现这个状态表示的是, 现在有一个线程正在表t上请求或者持有MDL写锁, 把select语句堵住了。
在MySQL 5.7版本下复现这个场景, 如图所示, 我给出了简单的复现步骤。
session A 通过lock table命令持有表t的MDL写锁, 而session B的查询需要获取MDL读锁。 所以, session B进入等待状态。
这类问题的处理方式, 就是找到谁持有MDL写锁, 然后把它kill掉。
问:如何找到是谁持有MDL写锁呢?
方式一:如果session A在加表锁后,接着执行了别的语句,那么便可通过执行show processlist命令找到造成阻塞的process id。
方式二:如果如果session A在加表锁后,没有执行任何命令,即Command列是“Sleep”。此时需要通过查询sys.schema_table_lock_waits这张表,找出造成阻塞的process id。(MySQL启动时需要设置performance_schema=on,MySQL5.5默认是关闭此功能的,若要开启,需手动在配置文件里添加,从MySQL5.6开始,默认打开此功能)
在上述场景下,另启一个session C,然后执行:
select blocking_pid from sys.schema_table_lock_waits;
执行结果:
最后,在找到造成阻塞的process id后,把这个连接用kill命令断开即可。
场景二:等flush
MySQL里面对表做flush操作的用法, 一般有以下两个:
-- flush指定table
flush tables t with read lock;--flush全部table
flush tables with read lock;
这两个flush语句, 如果指定表t的话, 代表的是只关闭表t; 如果没有指定具体的表名, 则表示关闭MySQL里所有打开的表。
正常情况下,这两个语句执行起来都很快, 除非它们也被别的线程堵住了。
所以, 出现Waiting for table flush状态的可能情况是: 有一个flush tables命令被别的语句堵住了, 然后它又堵住了我们的select语句。
注:flush table的作用,关闭表,并清空查询缓存。
现在, 我们一起来复现一下这种情况, 复现步骤如图所示:
在session A中, 我故意每行都调用一次sleep(1), 这样这个语句默认要执行10万秒, 在这期间表t一直是被session A“打开”着。 然后, session B的flush tables t命令再要去关闭表t, 就需要等session A的查询结束。 这样, session C要再次查询的话, 就会被flush 命令堵住了。
这个复现步骤的show processlist结果:
看到这个show processlist的结果, 肯定就知道应该怎么做了。
场景三:等行锁
经过了表级锁的考验, 我们的select 语句终于来到引擎里了。
select * from t where id=1 lock in share mode;
由于访问id=1这个记录时要加读锁, 如果这时候已经有一个事务在这行记录上持有一个写锁, 我们的select语句就会被堵住。
复现步骤和现场如下:
显然, session A启动了事务, 占有写锁, 还不提交, 是导致session B被堵住的原因。
问:等行锁的场景下,怎么查出是谁占着这个写锁呢?
答:如果是MySQL5.7及以上版本,可以通过sys.innodb_lock_waits 表查到。
查询方法:
select * from t sys.innodb_lock_waits where locked_table=`'test'.'t'`\G
执行结果:
可以看到, 这个信息很全, 4号线程是造成堵塞的罪魁祸首。 而干掉这个罪魁祸首的方式, 就是KILL 4。
查询慢
经过了重重封“锁”, 我们再来看看一些查询慢的例子。
先来看一条你一定知道原因的SQL语句:
select * from t where c = 50000 limit 1;
由于字段c上没有索引, 这个语句只能走id主键顺序扫描, 因此需要扫描5万行。
接下来, 我们再看一个只扫描一行, 但是执行很慢的语句。
select * from t where id = 1;
慢查询结果:
虽然扫描行数是1, 但执行时间却长达800毫秒。是不是有点奇怪呢, 这些时间都花在哪里了?
如果我把这个slow log的截图再往下拉一点, 你可以看到下一个语句, select * from t where id=1 lock in share mode, 执行时扫描行数也是1行, 执行时间是0.2毫秒。
看上去是不是更奇怪了? 按理说lock in share mode还要加锁, 时间应该更长才对啊。
场景复现:
session A先用start transaction with consistent snapshot(该命令启动事务时就创建了一致性视图)命令启动了一个事务, 之后session B才开始执行update 语句。session B更新完100万次, 生成了100万个回滚日志(undo log)。
session A在执行select * from t where id=1时,需要判断当前记录的可见性,由于session B执行了100万次,所以session A需要判断100万次,这也就是为什么select * from t where id=1语句执行的比较慢。
session A在执行select * from t where id=1 lock in share mode时,直接读最新记录即可,无需判断记录的可见性,所以执行的比较快。
上述两个语句的执行输出结果:
假设有如下表结构:
CREATE TABLE `t`(`id` int(11) NOT NULL,`c` int(11) DEFAULT NULL,`d` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY c (`c`)
) ENGINE=InnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);
小结:思考题
思考:如果执行如下语句,语句序列是怎么加锁的?锁又是什么时候释放的?
begin;
select * from t where c = 5 for update;
commit;
这个语句会命中d=5的这一行, 对应的主键id=5, 因此在select 语句执行完成后, id=5这一行会加一个写锁, 而且由于两阶段锁协议, 这个写锁会在执行commit语句的时候释放。
相关文章:

MySQL查询执行(四):查一行也很慢
假设存在表t,这个表有两个字段id和c,并且我在里面插入了10万行记录。 -- 创建表t CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB;-- 通过存储过程向t写入10w行数据 delimiter ;; create procedure idat…...

【Obsidian】当笔记接入AI,Copilot插件推荐
当笔记接入AI,Copilot插件推荐 自己的知识库笔记如果增加AI功能会怎样?AI的回答完全基于你自己的知识库余料,是不是很有趣。在插件库中有Copilot插件这款插件,可以实现这个梦想。 一、什么是Copilot? 我们知道githu…...
Spring Cloud集成Gateaway
Spring Cloud Gateway 是一个基于 Spring 生态的网关框架,用于构建微服务架构中的API网关。它可以对请求进行路由、过滤、限流等操作,是Spring Cloud微服务体系中常用的组件之一。下面介绍 Spring Cloud Gateway 的核心概念、应用场景以及简单的示例。 …...

如何准备技术面试?
大家好,我是老三,好久没更新了,翻出之前的一篇旧稿,是一篇总纲性质的文章——如何准备一场技术面试。这篇文章原本的开头是写给金三银四的,转眼就“金九银十”了,每一年都是最差的一年,又是未来…...

Kafka原理剖析之「Topic创建」
一、前言 Kafka提供了高性能的读写,而这些读写操作均是操作在Topic上的,Topic的创建就尤为关键,其中涉及分区分配策略、状态流转等,而Topic的新建语句非常简单 bash kafka-topics.sh \ --bootstrap-server localhost:9092 \ // …...
Java 高级学习路线概要~
前言:恭喜你已经掌握了 Java 的基础知识!现在,让我们踏上 Java 高级学习之旅,探索更强大的编程技巧和技术。学习前记得不要忘了巩固和加强基础的学习哦,高级学习也是建立在基础的学习之上。 1. 集合框架进阶 Map 接口…...

浏览器插件快速开启/关闭IDM接管下载
假设你已经为浏览器安装了IDM扩展,那么按下图的点击顺序,可以快速开启或关闭IDM的下载接管,而不必在IDM软件的设置->选项中,临时作调整。...

初识c++:入门基础
打字不易,留个赞再走吧~~ 目录 一.第一个c程序二.命名空间 namespace三.C输⼊&输出四.缺省参数 C兼容C语⾔绝⼤多数的语法,所以C语⾔实现的hello world依旧可以运⾏,C中需要把定义⽂件 代码后缀改为.cpp 一.第一个c程序 做好准备我们来写…...
Java Exception 异常相关总结
1.简介 在Java中,当代码运行有问题时会抛出异常,主要分为两类: 1.可以通过try...catch来捕获解决的,不影响后续执行的RuntimeException。 2.不可以通过代码解决的Exception。 为了提高代码的健壮性,我们会选择去捕…...

HighCharts图表自动化简介
什么是分析数据? 在任何应用程序中捕获并以图形或图表形式显示的分析数据是任何产品或系统的关键部分,因为它提供了对实时数据的洞察。 验证此类分析数据非常重要,因为不准确的数据可能会在报告中产生问题,并可能影响应用程序/系统的其他相关领域。 什么是HighChart? …...

使用LDAP登录GitLab
使用LDAP登录GitLab gitlab.rb 配置如下 gitlab_rails[ldap_enabled] true #gitlab_rails[prevent_ldap_sign_in] false###! **remember to close this block with EOS below** gitlab_rails[ldap_servers] YAML.load <<-EOSmain:label: LDAPhost: 172.16.10.180port:…...
【2024】前端学习笔记5-表单标签使用
表单是网页提供的一种交互式操作手段,主要用于采集用户输入的信息。 学习笔记 1.表单框架:form标签1.1.action属性:目标指向1.2.method属性:提交方式1.3.id属性:唯一标识1.4.placeholder属性:提示文字2.input标签2.1.text类型:基本文本输入2.2.password类型:密码输入2.…...
数据结构--二叉树(C语言实现,超详细!!!)
文章目录 二叉树的概念代码实现二叉树的定义创建一棵树并初始化组装二叉树前序遍历中序遍历后序遍历计算树的结点个数求二叉树第K层的结点个数求二叉树高度查找X所在的结点查找指定节点在不在完整代码 二叉树的概念 二叉树(Binary Tree)是数据结构中一种…...
【将字符串变为空的编辑距离】
题目描述 求由s串变成t串的编辑距离 在s串的开头/末尾添加一个字符,花费p 在s串的开头/末尾添加一个s串的子串,花费q 每次作都是基于当前的s串 s串初始为空 分析 等价于将一个字符串变为空串的过程 第一层按照长度遍历(如果按照下标i,j遍…...
卡特兰数的推理
卡特兰数(Catalan number),又称卡塔兰数、明安图数,是组合数学中一种常出现于各种计数问题中的数列。它以比利时数学家欧仁查理卡特兰的名字命名,但值得注意的是,这一数列的首次发现可以追溯到1730年&#…...

高精度治具加工的重要性和优势
在现代工业制造中,高精度治具加工扮演着举足轻重的角色。它不仅关乎产品制造的精度与质量,还直接影响到生产效率和成本控制。因此,时利和将深入探讨高精度治具加工的重要性和优势,对于提升工业制造水平具有重要意义。 高精度治具加…...
新版IDEA提示@Autowired不建议字段注入
随着项目的复杂度的增加,我们通常会在一个业务类中注入其他过多的业务类。从而使当前的业务层扩充成一个大而全的功能模块。那么就容易出现一下问题 字段注入会让依赖关系变得不那么明显,因为你无法通过构造函数看到所有的依赖项。使用构造函数时&#…...

adb的安装和使用 以及安装Frida 16.0.10+雷电模拟器
.NET兼职社区 .NET兼职社区 .NET兼职社区 1.下载adb Windows版本:https://dl.google.com/android/repository/platform-tools-latest-windows.zip 2.配置adb环境变量 按键windowsr打开运行,输入sysdm.cpl,回车。 高级》环境变量》系统变量》…...

解决移动端1px 边框优化的8个方法
前言 您是否注意到 1px 边框在移动设备上有时会显得比预期的要粗?这种不一致源于移动屏幕的像素密度不同。 在 Web 开发中,我们使用 CSS 来设置页面样式。但是,CSS 中的 1px 并不总是转换为设备上的物理 1px。这种差异就是我们的“1px 边框…...

频带宽度固定,如何突破数据速率的瓶颈?
目录 目录 引言 信道 频带宽度 信噪比 信噪比的重要性 影响信噪比的因素 码元 码元的特点: 码元与比特的关系: 码元的作用: 码元的类型: Question 类比解释: 技术解释: 引言 在现代通信系统中…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...