针对多线程的并发访问,任何一个数据库都有其锁定机制,它的优劣直接关系着数据的一致完整性与数据库系统的高并发处理性能。锁定机制也因此成了各种数据库的核心技术之一。不同数据库存储引擎的锁定机制是不同的,本文将从MySQL最常见的存储引擎MyISAM与InnoDB的锁定机制说起。

一、MyISAM的锁机制——表级锁定

MySQL表级锁定的常见类型主要分为两种,一种是读锁,一种是写锁。

谁持有读锁?谁持有写锁?谁在等待读锁资源?谁在等待写锁资源?数据库系统都是要记录的。MySQL中,主要通过如下4个队列来保存相关信息:

读锁持有队列:Current read-lock queue(lock->read)——存放所有正在锁定的读锁信息

写锁持有队列:Current write-lock queue(lock->write)——存放所有正在锁定的写锁信息

读锁等待队列:Pending read-lock queue(lock->read_wait)——存放所有等待对资源加读锁的线程信息

写锁等待队列:Pending write-lock queue(lock->write_wait)——存放所有等待对资源加写锁的线程信息

为保证数据一致完整性,多线程可以为同一份资源加多个读锁,而同一份资源只能加一个写锁,读锁与写锁也不能同时加在一份资源上。

1、读锁定

客户端请求获取读锁定资源时,如果满足如下两个要求,则请求通过,进入读锁持有队列;否则,请求失败,进入读锁等待队列。

(1)请求锁定的资源当前没有写锁定;

(2)写锁等待队列中没有优先级更高的写锁定在等待。

2、写锁定

客户端请求获取写锁定的时候:

(1)先通过写锁持有队列检查这份资源是否已经被加上写锁定,如果有,自然暂停自身线程进入写锁等待队列等待,如果没有,进行第(2)步

(2)检查写锁等待队列中是否有线程同样在等待获取这份资源的写锁定,如果有,则进入写锁等待队列等待,如果没有,进行第(3)步

(3)通过读锁持有队列检查这份资源是否已经被加上读锁定,如果有,则进行写锁等待队列等待,如果没有,可以获取写锁定,进入写锁持有队列中

请注意:对于MySQL使用者,展现出来的锁定类型只有读锁定与写锁定两种,但实际上,MySQL内部实现中却有11种枚举出来的锁定类型,因为表面与实现的差异,上述请求过程会有特例,在此不再赘述,如想深入了解,可参看简朝阳《MySQL性能调优与架构设计》。

那我们说,MyISAM在对表的操作上只能是串行处理,不能并行操作吗?并不是,MyISAM有一个很重要的机制就是并发插入(Concurrent Insert)特性,我们在下面第三部分MyISAM表级锁定优化建议再详细介绍。

二、InnoDB的锁机制——行级锁定

不光InnoDB存储引擎,MySQL的分布式存储引擎NDB Cluster都使用行级锁定。InnoDB的行级锁定同样分为两种,一种是共享锁,一种是排它锁。

1、当一个事务需要给某份资源加锁的时候,主要情况有如下

(1)如果遇到一个共享锁正锁定着资源,那么事务只能再加上一个共享锁,而不能加排它锁。

(2)如果遇到一个排他锁正锁定着资源,那么事务只能等待该锁定释放资源后他才能获得资源并添加自己的锁定。

2、InnoDB锁机制的实现与弊端

InnoDB锁机制是基于索引实现的,通过在指向数据记录的第一个索引键之前与最后一个索引键之后的空域空间(间隙或着说是范围)标记锁定信息实现,被称为间隙锁。

间隙锁的弊端:会在执行范围查询时,对范围内所有键值加锁,即使键值不存在,这会造成在加锁后无法插入锁定键值范围内的任何数据,影响性能。比如:

SELECT *

FROM user

WHERE user_id BETWEEM 1 AND 100

执行这个查询时,会对1-100范围内所有索引键值(1-100)加间隙锁,即使并不存在user_id为10的用户信息,所以在加锁后,要想插入一条user_id为10的用户信息是不可行的,这对于行级锁来说并不符合常理。InnoDB给出的解释是:为了防止幻读的出现。

当没有索引时或无法利用索引时,InnoDB会弃用行级锁,改用表级锁,并发处理性能降低。

另外,因为InnoDB的行级锁与事务处理特性,一定会产生死锁现象,对于如何降低死锁产生概率,我在第四部分InnoDB行级锁定优化建议中详述。

三、MyISAM表级锁定优化建议

因为表级锁的锁定颗粒较大,其实现难度复杂性行都降低了,成本自然降低,但是付出了高并发处理性能较低的代价,所以表级锁的优化就从如何提高并发处理性能说起。

1、缩短锁定时间

(1)降低查询复杂度,将复杂的查询划分成几个简单的查询分步进行。

(2)建立合适的索引加快查询效率。

(3)优化表结构,只存放必要的信息,且控制字段类型与字段长度(等长最优)。

2、利用MyISAM并发插入特性(Concurrent Insert),通过设置concurrent_insert参数实现

(1)concurrent_insert=2,无论MyISAM表数据文件的中间部分是否有因为删除数据留下的空闲空间,都允许在数据文件尾部进行并发插入。

(2)concurrent_insert=1,当MyISAM表数据文件中间不存在空闲空间时,才允许在数据文件尾部进行并发插入。

(3)concurrent_insert=0,无论MyISAM表数据文件的中间部分是否有因为删除数据留下的空闲空间,都不允许在数据文件尾部进行并发插入。

如果数据被删除的可能性比较小,而且对暂时性浪费并不在乎的话,可以尝试把concurrent_insert设置为2;但当删除量不是很小,查询时需要读取更多的空域空间时,推荐设置为1。

3、合理利用读写优先级

默认情况下,写优先级要高于读优先级。

(1)当数据库系统以读为主,要优先保证查询性能时,可通过low_priority_updates=1设置读优先级高于写优先级。

(2)当数据库系统需要保证写入性能,则不用设置low_priority_updates参数。

四、InnoDB行级锁定优化建议

InnoDB的行级锁最大的优势就是增强了高并发的处理能力,缺点就是复杂性较高、易死锁,且基于索引实现有一定弊端。我们要做的就是扬长避短,合理利用InnoDB行级锁定,为此我们就应该做的:

1、尽可能让所有的数据检索都通过索引实现,因为InnoDB行级锁是基于索引实现的,没有索引或无法使用索引系统会改为使用表级锁。

2、合理设计索引,以缩小加锁范围,避免“间隙锁”造成不该锁定的键值被锁定。

3、尽量控制事务的大小,因为行级锁的复杂性会加大资源量以及锁定时间。

4、使用较低级别的事务隔离,以减少因实现事务隔离而付出的成本。

5、避免死锁,可以通过如下方式实现:

(1)类似的业务模块中,尽可能按照相同的访问顺序来访问,防止产生死锁。

(2)同一个事务中,尽量做到一次性锁定需要的所有资源。

(3)对于易产生死锁的业务部分,增大处理颗粒度,升级为表级锁以降低死锁产生的概率。

mysql sql优化与调优机制详解_MySQL性能调优——锁定机制与锁优化分析详解相关推荐

  1. Spark商业案例与性能调优实战100课》第20课:大数据性能调优的本质和Spark性能调优要点分析

    Spark商业案例与性能调优实战100课>第20课:大数据性能调优的本质和Spark性能调优要点分析 基于本元想办法,大智若愚,大巧若拙!深入彻底的学习spark技术内核!

  2. mysql dba工作笔记pdf_社区专家在线:Oracle数据库、MySQL、Db2 等数据库日常运维故障与性能调优在线答疑...

    数据库的重要性毋庸置疑,随着数据量日益增加,数据库的重要性更为凸显.DBA们作为数据库的日程运维管理人员,肩负着数据库运维的重要使命.一名合格的DBA,日常工作中需要掌握多项技能,包括数据库的故障诊断 ...

  3. 一步步带你详解JVM性能调优

    性能调优 性能调优包含多个层次,比如:架构调优.代码调优.JVM调优.数据库调优.操作系统调优等. 架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的. 性能调优基本上按照以下步骤进 ...

  4. server sql top速度变慢解决方案_SQL Server的性能调优:解决查询速度慢的五种方法-数据库...

    编辑推荐: 本文主要通过一下几个方面介绍:使用SQL DMV查找慢速查询.通过APM解决方案查询报告.SQL Server扩展事件.SQL Azure查询性能洞察等相关内容. 本文来自博客园,由火龙果 ...

  5. 鲲鹏性能优化十板斧(三)——网络子系统性能调优

    1 网络子系统性能调优 3.1  调优简介 3.2  常用性能监测工具 3.3  优化方法 1.1 调优简介 调优思路 本章主要是围绕优化网卡性能和利用网卡的能力分担CPU的压力来提升性能.在高并发的 ...

  6. mysql性能调优 高可用_MySQL性能调优与架构设计——第 17 章 高可用设计之思路及方案...

    第 17 章 高可用设计之思路及方案 前言: 数据库系统是一个应用系统的核心部分,要想系统整体可用性得到保证,数据库系统就不能出现任何问题.对于一个企业级的系统来说,数据库系统的可用性尤为重要.数据库 ...

  7. 鲲鹏性能优化十板斧——鲲鹏处理器NUMA简介与性能调优五步法

    TaiShan特战队六月底成立,至今百日有余,恰逢1024程序员节,遂整理此文,献礼致敬!希望能为广大在鲲鹏处理器上开发软件.性能调优的程序员们,提供一点帮助.从今天开始,将陆续推出性能调优专题文章. ...

  8. java 内存调优_JVM内存模型以及性能调优

    JVM 内存模型 JVM.png 程序计数器 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.分支.循环.跳转.异常处理.线程恢复等基础功能都需要依赖这个计数器来完成. ...

  9. 易语言mysql锁表_MySQL的3种锁定机制

    MySQL各存储引擎使用了3种类型的锁定机制: 1. 行级锁定(row-level) --- MyISAM.Memory.CSV *锁定对象颗粒度最小,发生资源争用的概率最小,在并发处理能力上有较大优 ...

  10. linux mysql io压力大_MySQL性能调优(四) Linux 磁盘IO

    1. IO处理过程 磁盘IO经常会成为系统的一个瓶颈,特别是对于运行数据库的系统而言.数据从磁盘读取到内存,在到CPU缓存和寄存器,然后进行处理,最后写回磁盘,中间要经过很多的过程,下图是一个以wri ...

最新文章

  1. linux能远程打开桌面版,如何从Linux上远程显示Windows桌面
  2. python空气质量分析报告_Python数据可视化:2018年北上广深空气质量分析
  3. VTK:Qt之ImageDataToQImage
  4. ClientDataSet建立索引和排序
  5. 冒泡算法代码java_java版本的冒泡算法
  6. c语言计算日期天数,关于计算两个日期间天数的代码,大家来看看
  7. CSS定义表格边框大全(细线/虚线/点线)
  8. Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果
  9. __declspec(dllimport)和__declspec(dllexport)的区别,以及有关c/c++调用约定
  10. 压力测试工具Siege详解
  11. mysql英文版怎么调中文_MySQL英文版的使用
  12. 马尔可夫不等式 Markov's inequality
  13. 咖啡的合适温度(前缀和以及加减标记)
  14. ireport 循环_IReport 常见问题整理
  15. ieTEST停止工作bug修复
  16. 定义一个鸭子的类java_2019-02-11——Java 鸭子模型
  17. 驱动开发:Win10枚举完整SSDT地址表
  18. Playbooks 简介
  19. 消防气体灭火系统(一)
  20. SILC 超像素分割代码

热门文章

  1. 10.TCP/IP 详解卷1 --- 动态选路协议
  2. 6. 标准 I/O 库
  3. 62. 拆分初始化负载
  4. oracle错误输出,oracle – SQL小提琴输出错误
  5. mysql 批量更新_MySQL批量更新
  6. typeof的用法 typeof的返回值是一个字符串 返回的字符串类别
  7. jerasure 2.0译文
  8. Android之apk优化
  9. 创建类模式(零):简单/静态工厂(Static Factory)
  10. SVN服务器端安装过程出现“Custom action InstallWMISchemaExecute failed:无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动。”