MySQL锁机制及其优化

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 概述 在一般的数据库驱动的业务中,很大的一个难点就是:在最大程度地利用数据库的并发访问的同时,还要确保每个用户能以一致的方式读取和修改数据,为此,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技术内幕》,相关博文

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
存储 关系型数据库 MySQL
MySQL MVCC全面解读:掌握并发控制的核心机制
【10月更文挑战第15天】 在数据库管理系统中,MySQL的InnoDB存储引擎采用了一种称为MVCC(Multi-Version Concurrency Control,多版本并发控制)的技术来处理事务的并发访问。MVCC不仅提高了数据库的并发性能,还保证了事务的隔离性。本文将深入探讨MySQL中的MVCC机制,为你在面试中遇到的相关问题提供全面的解答。
143 2
|
27天前
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
1月前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
70 3
|
1月前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
72 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万级数据统计优化实践
【10月更文挑战第21天】 在处理大规模数据集时,传统的单体数据库解决方案往往力不从心。MySQL和Redis的组合提供了一种高效的解决方案,通过将数据库操作与高速缓存相结合,可以显著提升数据处理的性能。本文将分享一次实际的优化案例,探讨如何利用MySQL和Redis共同实现百万级数据统计的优化。
94 9
|
1月前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
192 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
67 5
|
2月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
100 1
|
1月前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
78 0
|
2月前
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
222 0