行锁升级表锁如何避免?表锁后如何排查?

2024-04-03 20:36

本文主要是介绍行锁升级表锁如何避免?表锁后如何排查?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、那些场景会造成行锁升级表锁

说明:

InnoDB引擎3种行锁算法(Record Lock、Gap Lock、Next-key Lock)都是锁定的索引。

当触发X锁(写锁)的where条件 无索引 或 索引失效 时,查询的方式就变成全表扫描,也就是扫描所有的聚集索引记录。

为什么要把不匹配的记录也加锁呢?

这里针对的是默认的事务隔离级别:可重复读(RR),因为要解决 不可重复读 和 幻读问,所以在遍历扫描聚集索引记录时,为了防止扫描过的索引被其他事务修改(不可重复读问题) 或 间隙被其他事务插入记录(幻读问题),从而导致数据不一致,所以MYSQL的解决方案就是 把所有扫描过的索引记录和间隙都锁上,这时也就出现了我们看到的锁表。

无索引:

例如下面的sql,remark 列不是索引列,如果按照remark列更新就是无索引更新

UPDATE user_info SET user_name = 'keke' WHERE remark = 'keke1'

索引失效:

explain验证:

索引失效的场景很多,我们可以用explain验证:

explain 返回的 key 不是你期望的索引,而是primary;

explain 返回的 type 是 index 或 all

MYSQL成本计算分析认为全表扫描成本更低时:

同样的SQL,传入的参数不同,explain 的结果也不同,有时会走索引、有时索引又会失效!

这里的原因是:更具传入的入参不同、导致 结果集不同。再正式扫描前、MYSQL会进行成本计算。计算走那个索引快,就算命中了索引,但是发现还不如全表扫描快,那么也会不走索引,而是进行全表扫描,这时就会导致索引失效!

关于成本计算:它是先计算不同索引的I/O成本 和 CPU成本,然后进行对比,那个成本低就选择那个执行!

二、如何避免:

1.禁止 WHERE 条件使用无索引列进行 更新/删除

2.尽可能使用聚集索引进行更新/删除

3.如果确实需要用到 非聚集索引进行更新/删除时:

使用explain检测索引是否会失效

避免对索引列进行 类型转换、函数、运算符等会造成升级的操作!

尽可能减少检索条件范围,范围越大就越可能被MySQL成本计算太高,从而导致索引失效!

4.尽可能控制事务的大小、减少锁定的时间

5.使用读已提交(RC)事务隔离级别

读已提交(RC)事务隔离级别,由于没有间隙锁(Gap Lock),所以它的加锁规则相对简单,都是针对匹配索引记录加的Record Lock、因为不用解决 不可重复读 和 幻读 问题,所以也就不存在 锁表了

三、锁表应该如何分析排查

查看InnoDB_row_lock%相关变量

show status like 'innodb_row_lock%';

字段

说明

Innodb_row_lock_current_waits

当前正在等待锁定的数量

Innodb_row_lock_time

等待总时长: 从系统启动到现在锁定总时间长度

Innodb_row_lock_time_avg

等待平均时长: 每次等待所花平均时间

Innodb_row_lock_time_max

从系统启动到现在等待最长的一次所花时间

Innodb_row_lock_waits

等待总次数: 系统启动后到现在总共等待的次数

四、查看 INFORMATION_SCHEMA系统库

可以通过 INFORMATION_SCHEMA系统库提供的:查看事务、锁、锁等待的 数据表 来分析

系统表

说明

INNODB_TRX

查看事务

INNODB_LOCKS

查看锁

INNODB_LOCK_WAITS

查看锁等待

PROCESSLIST

查看连接情况

INNODB_TRX:

下面对 innodb_trx 表的每个字段进行解释:

字段

说明

trx_id

事务ID。只读事务和非锁事务是不会创建id的

trx_state

事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING

trx_started

事务开始时间

trx_requested_lock_id

事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息

trx_wait_started

事务开始等待的时间

trx_weight

事务的权重。代表修改的行数和被事务锁住的行数。为了解决死锁,innodb会选择一个高度最小的事务来当做牺牲品进行回滚。已经被更改的非交易型表的事务权重比其他事务高,即使改变的行和锁住的行比其他事务低。

trx_mysql_thread_id

事务线程 ID,可以和 PROCESSLIST 表 JOIN

trx_query

事务正在执行的 SQL 语句。

trx_operation_state

事务当前操作状态

trx_tables_in_use

当前事务执行的 SQL 中使用的表的个数

trx_tables_locked

当前执行 SQL 的行锁数量。因为只是行锁,不是表锁,表仍然可以被多个事务读和写

trx_lock_structs

事务保留的锁数量。

trx_lock_memory_bytes

事务锁住的内存大小,单位为 BYTES

trx_rows_locked

事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行

trx_rows_modified

事务更改的行数。

trx_concurrency_tickets

该值代表当前事务在被清掉之前可以多少工作,由 innodb_concurrency_tickets系统变量值指定。

trx_isolation_level

当前事务的隔离级别

trx_unique_checks

是否打开唯一性检查的标识

trx_foreign_key_checks

是否打开外键检查的标识

trx_last_foreign_key_error

最后一次的外键错误信息

trx_adaptive_hash_latched

自适应哈希索引是否被当前事务阻塞。当自适应哈希索引查找系统分区,一个单独的事务不会阻塞全部的自适应hash索引。自适应hash索引分区通过 innodb_adaptive_hash_index_parts参数控制,默认值为8

trx_adaptive_hash_timeout

是否为了自适应hash索引立即放弃查询锁,或者通过调用mysql函数保留它。当没有自适应hash索引冲突,该值为0并且语句保持锁直到结束。在冲突过程中,该值被计数为0,每句查询完之后立即释放门闩。当自适应hash索引查询系统被分区(由 innodb_adaptive_hash_index_parts参数控制),值保持为0

INNODB_LOCKS:

只有发生阻塞才会有数据,可以查看上锁的详细信息

字段

说明

lock_id

锁 ID

lock_trx_id

拥有锁的事务 ID。可以和 INNODB_TRX 表 JOIN 得到事务的详细信息。

lock_mode

锁的模式。有如下锁类型:行级锁包括:S、X、IS、IX,分别代表:共享锁、排它锁、意向共享锁、意向排它锁。表级锁包括:S_GAP、X_GAP、IS_GAP、IX_GAP 和 AUTO_INC,分别代表共享间隙锁、排它间隙锁、意向共享间隙锁、意向排它间隙锁和自动递增锁。

lock_type

锁的类型

lock_table

被锁定的或者包含锁定记录的表的名称。

lock_index

当 LOCK_TYPE=’RECORD’ 时,表示索引的名称;否则为 NULL。

lock_space

当 LOCK_TYPE=’RECORD’ 时,表示锁定行的表空间 ID;否则为 NULL。

lock_page

当 LOCK_TYPE=’RECORD’ 时,表示锁定行的页号;否则为 NULL。

lock_rec

当 LOCK_TYPE=’RECORD’ 时,表示一堆页面中锁定行的数量,亦即被锁定的记录号;否则为 NULL。

lock_data

当 LOCK_TYPE=’RECORD’ 时,表示锁定行的主键;否则为NULL。

INNODB_LOCK_WAITS:

只有发生锁等待才有数据,可以通过此表找出阻塞的事务ID 和 锁ID

字段

说明

requesting_trx_id

请求的事务ID

requested_lock_id

事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN。

blocking_trx_id

阻塞的事务ID

blocking_lock_id

某一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN。

PROCESSLIST:

可以查看连接情况,通过这张表我们可以看到事务所在的主机

字段

说明

ID

线程ID, 可以JOIN INNODB_TRX.trx_requested_lock_id

USER

连接用户

HOST

连接主机 ip:port

DB

连接的数据库

五、如何kill某个事务:

通过对上面的表进行查询, 当我们发现某个事务阻塞了很多事务, 并且执行时间很长时, 我们可以手动中止它。

只需要找到INNODB_TRX 表的trx_mysql_thread_id字段,然后调用kill命令即可:

kill {INNODB_TRX.trx_mysql_thread_id}

学习自:【MySQL】说透锁机制(三)行锁升表锁如何避免? 锁表了如何排查?_为什么断开连接避免锁表-CSDN博客

这篇关于行锁升级表锁如何避免?表锁后如何排查?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

macOS升级后SVN升级

问题 svn: error: The subversion command line tools are no longer provided by Xcode. 解决 sudo chown -R $(whoami) /usr/local/Cellar brew install svn

如何来避免FOUC

FOUC(Flash of Unstyled Content)是指在网页加载过程中,由于CSS样式加载延迟或加载顺序不当,导致页面出现短暂的无样式内容闪烁现象。为了避免FOUC,可以采取以下几种方法: 1. 优化CSS加载 内联CSS:将关键的CSS样式直接嵌入到HTML文档的<head>部分,这样可以确保在页面渲染之前样式就已经加载和应用。提前引入CSS:将CSS文件放在HTML文档的<he

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

JeecgBoot 升级springboot版本到2.6.0

1. 环境描述 Jeecgboot 3.0,他所依赖的springboot版本为2.3.5Release,将springboot版本升级为2.6.0。过程全纪录,从2开始描述。 2. 修改springboot版本号 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-pare

网络故障排查和tcpdump抓包

网络故障排查: ping一台服务器不通,你如何排查 检查本机ip地址设置  网关和dns服务器是否设置正确 或者ip地址冲突能否上网 看路由器是否有问题 ping服务器是否运行服务器禁止ping   防火墙设置 iptables -A INPUT -P ICMP -j DROPiptables -D INPUT -P ICMP -j DROP用户不能访问服务器 怎么排查 检查用户网络连接检查服

欧拉系统 kernel 升级、降级

系统版本  cat  /etc/os-release  NAME="openEuler"VERSION="22.03 (LTS-SP1)"ID="openEuler"VERSION_ID="22.03"PRETTY_NAME="openEuler 22.03 (LTS-SP1)"ANSI_COLOR="0;31" 系统初始 kernel 版本 5.10.0-136.12.0.

Zookeeper集群是如何升级到新版本的

方案1:复用老数据方案 这是经过实践的升级方案,该方案是复用旧版本的数据,zk集群拓扑,配置文件都不变,只是启动的程序为最新的版本。 参考文章: Zookeeper集群是如何升级到新版本的 方案2:重新建立数据方案 该方案的思路是:先停掉一台follower的机器上的服务,然后加入一个新版本的zk(zk的数据目录是空的),然后启动新zk,之后新zk会把旧集群中的数据同步过来。之后再操作另

Qt: 详细理解delete与deleteLater (避免访问悬空指针导致程序异常终止)

前言 珍爱生命,远离悬空指针。 正文 delete 立即删除:调用 delete 后,对象会立即被销毁,其内存会立即被释放。调用顺序:对象的析构函数会被立即调用,销毁该对象及其子对象。无事件处理:如果在对象销毁过程中还涉及到信号和槽、事件处理等,直接 delete 可能会导致问题,尤其是在对象正在处理事件时。适用场景:适用于在确定对象已经不再被使用的情况下,并且不涉及异步处理或事件循环中的

mysql数据库8.0小版本原地升级

mysql数据库8.0小版本原地升级 准备工作升级工作停库使用新版本软件启动数据库更新环境变量重启数据库 升级日志 OS release: CentOS 7.9升级前DB version: MySQL 8.0.30数据库升级安装包:mysql-8.0.36-linux-glibc2.12-x86_64.tar.xzMySQL Shell安装包:mysql-shell-8.0.36