MySQL锁机制及其优化

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 概述 在一般的数据库驱动的业务中,很大的一个难点就是:在最大程度地利用数据库的并发访问的同时,还要确保每个用户能以一致的方式读取和修改数据,为此,MySQL就有了锁(locking)的机制。频繁出现的锁的不仅本身消耗着资源,也影响着数据库的运行性能,因此,做好数据库的锁优化,对于数据库的性能具有很大意义。

概述

在一般的数据库驱动的业务中,很大的一个难点就是:在最大程度地利用数据库的并发访问的同时,还要确保每个用户能以一致的方式读取和修改数据,为此,MySQL就有了锁(locking)的机制。频繁出现的锁的不仅本身消耗着资源,也影响着数据库的运行性能,因此,做好数据库的锁优化,对于数据库的性能具有很大意义。

锁的定义

锁是数据库系统区别文件系统的一个关键特性。锁机制是用于管理对共享资源的并发访问。
在MySQL中,lock和latch都可以被称为锁,但是两者具有不同的意义:

latch 一般称为闩锁,要求锁定的时间非常短,在innodb引擎中,latch又可分为mutex(互斥锁)和rwlock(读写锁),目的是用来保证并发线程操作临界资源的正确性,通常没有死锁检测的机制

lock的对象是事务,用来锁定的是数据库中的对象,如表,页,行。并且在commit或rollback后释放(不同的隔离级别的释放时间可能不同)

innodb中锁的类型

innodb实现了两种标准行级锁
共享锁(S Lock):允许事物读一行数据
排他锁(X lock):允许事物删除或更新一条数据

此外,innodb支持多颗粒锁定,这种锁定允许事务在行级别上的锁和表级上的锁同时存在,为此,innodb支持一种额外的锁方式:意向锁
意向锁将锁定的对象分为多个层次如: 数据库 > 表 > 页 > 记录,并且规定,要想对最细粒度的对象上锁,那么首先要对粗粒度的对象上锁,就如要想对一行记录加上X锁,就必须在该行所在的数据库,表,页先上意向锁IX,最后对行记录加上X锁。

innodb存储引擎支持意向锁设计比较简练,其意向锁为表级别的锁目的是为了在一个事物中揭示下一行被请求的锁类型,意向锁分为两种:
1)意向共享锁,事物想要获得一张表中某几行的共享锁
2)意向排他锁,事物想要获得一张表中某几行的排他锁

由于支持的是行级别的锁,所以意向锁不会阻塞全表扫以外的任何请求,其兼容性如下:

1 IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不 兼容 兼容 不兼容

以上,是MySQL锁的基本知识

latch的优化

对于innodb中的latch,可以通过以下命令查看

mysql>show engine innodb mutex;
+----------------+-----------------------------+------------------+
| Type | Name | Status |
+----------------+-----------------------------+------------------+
| InnoDB | rwlock: dict0dict.cc:1184 | waits=90 |
| InnoDB | rwlock: log0log.cc:838 | waits=189885 |
| InnoDB | sum rwlock: buf0buf.cc:1460 | waits=2 |
+----------------+-----------------------------+------------------+
返回行数:[3],耗时:698 ms.

列type显示的总是Innodb,列name显示的是latch的信息以及所在源码的位置(行数),列status显示的是等待的次数
上述所有的这些信息都是比较底层的,一般仅供开发人员参考

MySQL表锁的优化

和行级锁定相反,表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。

当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。

优化建议:
1)建议将表切换为innodb 存储引擎,减少表级别锁出现概率
2)优化select语句,使其能在更短的时间内完成查询,减少表锁时间
3)对于只使用表级锁的存储引擎(如MyISAM、MEMORY和MERGE),启用--low-priority-updates模式,使所有更新表的语句的优先级都低于SELECT语句

也可考虑赋予特定insert,update,delete语句更低的优先级

4)在查询语句中使用SQL_BUFFER_RESULT(查询缓存),来减少表被锁定的时间
5)将大的表转为separate tables,因为允许对一个表中的列运行查询,而更新仅限于不同表中的列。

innodb行锁的优化

Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定的。当系统并发量较高的时候,Innodb的整体性能和MyISAM相比就会有比较明显的优势了。但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差。

要想合理利用Innodb的行级锁定,做到扬长避短,我们必须做好以下工作:
1)尽可能让所有的数据查询都通过索引来完成,从而避免Innodb因为无法通过索引键加锁而升级为表级锁定;
2)合理设计索引,让Innodb在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他查询的执行;
3)尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录;
4)尽量控制事务的大小,减少锁定的资源量和锁定时间长度;

对于Innodb所使用的行级锁定,系统中是通过另外一组更为详细的状态变量来记录的,如下:

mysql>show status like 'innodb_row_lock%'
+-------------------------------+-----------------+
| Variable_name | Value |
+-------------------------------+-----------------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 0 |
| Innodb_row_lock_time_avg | 0 |
| Innodb_row_lock_time_max | 0 |
| Innodb_row_lock_waits | 0 |
+-------------------------------+-----------------+
返回行数:[5],耗时:4 ms.

Innodb 的行级锁定状态变量不仅记录了锁定等待次数,还记录了锁定总时长,每次平均时长,以及最大时长,此外还有一个非累积状态量显示了当前正在等待锁定的等待数量。对各个状态量的说明如下:

Innodb_row_lock_current_waits:当前正在等待锁定的数量;
Innodb_row_lock_time:从系统启动到现在锁定总时间长度;
Innodb_row_lock_time_avg:每次等待所花平均时间;
Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
Innodb_row_lock_waits:系统启动后到现在总共等待的次数;

对于这5个状态变量,比较重要的主要是Innodb_row_lock_time_avg(等待平均时长),Innodb_row_lock_waits(等待总次数)以及Innodb_row_lock_time(等待总时长)这三项。尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划。

死锁优化

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种相互等待的现象。若无外力作用,事务都将无法推进下去。

一般的,解决死锁的问题的最简单的方式是不要有等待,将任何等待都转化为回滚,并且事务重新开始

死锁优化的第一步就是设置合理的锁超时时间,不要存在长时间所等待的情况

mysql>show variables like '%innodb_lock_wait%'
+--------------------------+-----------------+
| Variable_name | Value |
+--------------------------+-----------------+
| innodb_lock_wait_timeout | 50 |
+--------------------------+-----------------+
返回行数:[1],耗时:4 ms.

一旦发生死锁,需要及时处理,下列信息可以让运维人员及时发现死锁的问题

mysql>show engine innodb status\G
TRANSACTIONS
------------
Trx id counter 295495
Purge done for trx's n:o < 295495 undo n:o < 0 state: running but idle
History list length 31
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421494576134400, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421494576130752, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421494576131664, not started
0 lock struct(s), heap size 1136, 0 row lock(s)

结语

总之,优化锁的最好方法就是尽量避免锁等待的发生,在高并发和锁消耗直接找到一个性能的平衡点,对于用户来说,根据自己的业务特点和要求,正确的进行锁优化,是提高系统性能重要的一个步骤。

学习参考资料:MySQL5.7文档,《MySQL技术内幕》,相关博文

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
关系型数据库 MySQL Linux
MySQL原理简介—6.简单的生产优化案例
本文介绍了数据库和存储系统的几个主题: 1. **MySQL日志的顺序写和数据文件的随机读指标**:解释了磁盘随机读和顺序写的原理及对数据库性能的影响。 2. **Linux存储系统软件层原理及IO调度优化原理**:解析了Linux存储系统的分层架构,包括VFS、Page Cache、IO调度等,并推荐使用deadline算法优化IO调度。 3. **数据库服务器使用的RAID存储架构**:介绍了RAID技术的基本概念及其如何通过多磁盘阵列提高存储容量和数据冗余性。 4. **数据库Too many connections故障定位**:分析了MySQL连接数限制问题的原因及解决方法。
|
12天前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
3天前
|
SQL 关系型数据库 MySQL
MySQL底层概述—10.InnoDB锁机制
本文介绍了:锁概述、锁分类、全局锁实战、表级锁(偏读)实战、行级锁升级表级锁实战、间隙锁实战、临键锁实战、幻读演示和解决、行级锁(偏写)优化建议、乐观锁实战、行锁原理分析、死锁与解决方案
MySQL底层概述—10.InnoDB锁机制
|
4天前
|
缓存 算法 关系型数据库
MySQL底层概述—8.JOIN排序索引优化
本文主要介绍了MySQL中几种关键的优化技术和概念,包括Join算法原理、IN和EXISTS函数的使用场景、索引排序与额外排序(Using filesort)的区别及优化方法、以及单表和多表查询的索引优化策略。
MySQL底层概述—8.JOIN排序索引优化
|
4天前
|
SQL 关系型数据库 MySQL
MySQL底层概述—7.优化原则及慢查询
本文主要介绍了:Explain概述、Explain详解、索引优化数据准备、索引优化原则详解、慢查询设置与测试、慢查询SQL优化思路
MySQL底层概述—7.优化原则及慢查询
|
5天前
|
存储 缓存 关系型数据库
MySQL底层概述—5.InnoDB参数优化
本文介绍了MySQL数据库中与内存、日志和IO线程相关的参数优化,旨在提升数据库性能。主要内容包括: 1. 内存相关参数优化:缓冲池内存大小配置、配置多个Buffer Pool实例、Chunk大小配置、InnoDB缓存性能评估、Page管理相关参数、Change Buffer相关参数优化。 2. 日志相关参数优化:日志缓冲区配置、日志文件参数优化。 3. IO线程相关参数优化: 查询缓存参数、脏页刷盘参数、LRU链表参数、脏页刷盘相关参数。
MySQL底层概述—5.InnoDB参数优化
|
2天前
|
关系型数据库 MySQL 网络安全
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
40 25
|
7天前
|
关系型数据库 MySQL 数据库
从MySQL优化到脑力健康:技术人与效率的双重提升
聊到效率这个事,大家应该都挺有感触的吧。 不管是技术优化还是个人状态调整,怎么能更快、更省力地完成事情,都是我们每天要琢磨的事。
56 23
|
7天前
|
SQL 关系型数据库 MySQL
MySQL原理简介—11.优化案例介绍
本文介绍了四个SQL性能优化案例,涵盖不同场景下的问题分析与解决方案: 1. 禁止或改写SQL避免自动半连接优化。 2. 指定索引避免按聚簇索引全表扫描大表。 3. 按聚簇索引扫描小表减少回表次数。 4. 避免产生长事务长时间执行。
|
24天前
|
监控 关系型数据库 MySQL
Aurora MySQL负载突增应对策略与优化方案
通过以上策略,企业可以有效应对 Aurora MySQL 的负载突增,确保数据库在高负载情况下依然保持高性能和稳定性。这些优化方案涵盖了从架构设计到具体配置和监控的各个方面,能够全面提升数据库的响应速度和处理能力。在实际应用中,应根据具体的业务需求和负载特征,灵活调整和应用这些优化策略。
50 22