针对多线程的并发访问,任何一个数据库都有其锁定机制,它的优劣直接关系着数据的一致完整性与数据库系统的高并发处理性能。锁定机制也因此成了各种数据库的核心技术之一。不同数据库存储引擎的锁定机制是不同的,本文将从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的锁相关知识,参阅:MySQL锁详解

MySql(七):MySQL性能调优——锁定机制与锁优化分析的更多相关文章

  1. MySQL性能调优——锁定机制与锁优化分析

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

  2. mysql监控、性能调优及三范式理解

    原文:mysql监控.性能调优及三范式理解 1监控 工具:sp on mysql     sp系列可监控各种数据库 2调优 2.1 DB层操作与调优 2.1.1.开启慢查询 在My.cnf文件中添加如 ...

  3. MySQL插入数据性能调优

    插入数据性能调优总结: 1.SQL插入语句调优 2.如果是InnoDB引擎的话,尝试开启事务,批量提交 3.调整MySQl数据库配置     参考: 百度空间 - MySQL插入数据性能调优 CSDN ...

  4. Spark性能调优之代码方面的优化

    Spark性能调优之代码方面的优化 1.避免创建重复的RDD     对性能没有问题,但会造成代码混乱   2.尽可能复用同一个RDD,减少产生RDD的个数   3.对多次使用的RDD进行持久化(ca ...

  5. sql server 性能调优之 CPU消耗最大资源分析1 (自sqlserver服务启动以后)

    一. 概述 上次在介绍性能调优中讲到了I/O的开销查看及维护,这次介绍CPU的开销及维护, 在调优方面是可以从多个维度去发现问题如I/O,CPU,  内存,锁等,不管从哪个维度去解决,都能达到调优的效 ...

  6. mysql my.ini 性能调优

    MYSQL服务器my.cnf配置文档详解 硬件:内存16G [client] port = 3306 socket = /data/3306/mysql.sock [mysql] no-auto-re ...

  7. mysql之sql性能调优

    sql调优大致分为两步:1 如何定位慢查询   2 如何优化sql语句. 一:定位慢查询 -- 显示到mysql数据库的连接数 -- show status like 'connections'; - ...

  8. 性能调优必备:NIO的优化实现原理

    前言 我们就从底层的网络 I/O 模型优化出发,再到内存拷贝优化和线程模型优化,深入分析下 Tomcat.Netty 等通信框架是如何通过优化 I/O 来提高系统性能的. 网络 I/O 模型优化 网络 ...

  9. MySql(十一):MySQL性能调优——常用存储引擎优化

    一.前言 MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.本章将介绍最为常用的两种存储引擎进行针对性的优化建议. 二.MyISAM存储 ...

随机推荐

  1. easyui form validate总是返回false原因

    最近做表单验证用了easyui form组件.又一次发现在测试表单都填写正确了但是调试表单的代码监测到调用form的"validate"方法总是返回false 最后查了一下原因在h ...

  2. MySQL监控主要指标及采集方法

    MySQL监控属于DB监控的模块之一,包括采集.展示.监控告警.本文主要介绍MySQL监控的主要指标和采集方法. MySQL监控和Redis监控的逻辑类似,可参考文章<Redis监控主要指标及采 ...

  3. IMA文件如何打开,winimage使用方

    一般先用UltraISO打开一个系统的镜像文件(.iso).其中有些文件(尤其是.ima,img)比如下面雨林木风Ghost系统盘的这个IMA文件,我们先提取到桌面 用WinImage打开这个文件即可 ...

  4. struts2学习笔记(3)---Action中訪问ServletAPI获取真实类型的Servlet元素

    一.源码: struts.xml文件: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE s ...

  5. WebService SOAP、Restful和HTTP(post/get)请求区别

    web service(SOAP) Webservice的一个最基本的目的就是提供在各个不同平台的不同应用系统的协同工作能力. Web service 就是一个应用程序,它向外界暴露出一个能够通过We ...

  6. git命令 add -a和add .和add -u 的区别

    总结: git add -a 所有的更改操作--新建,更改,删除: git add . 只包括 新建 ,修改操作:无删除: git add -u 只包括修改,删除操作,无新建: 示例: git ini ...

  7. 设置tableViewCell背景颜色

    1 2 3 4 5 6 7 8 9 10 11 12 13 //方法一: cell.contentView.backgroundColor = [UIColor redColor]; //方法二: U ...

  8. 应用程序正常初始化(0xc0000135)失败的解决方法

    转自:http://blog.sina.com.cn/s/blog_64fba4e00100mzf9.html 这是由于没有安装.NET framework 所造成的,请安装.NET framewor ...

  9. MySQL优化小案例:连接数

    错误代码:MySQL: ERROR 1040: Too many connections 经常会遇到这个错误,要么是业务增长,正常的访问量增多,要么是自己的max_connections设置的过小了 ...

  10. cordova 强制竖屏

    orentation的默认值是default 可使用的值有:default, landscape (横屏), portait (竖屏) orentation可以将设备锁定方向,不受设备旋转影响. 方案 ...