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

  1. MySql(七):MySQL性能调优——锁定机制与锁优化分析

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

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

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

  3. MySQL性能调优与架构设计——第7章 MySQL数据库锁定机制

    第7章 MySQL数据库锁定机制 前言: 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核 ...

  4. MySQL性能调优与架构设计——第 18 章 高可用设计之 MySQL 监控

    第 18 章 高可用设计之 MySQL 监控 前言: 一个经过高可用可扩展设计的 MySQL 数据库集群,如果没有一个足够精细足够强大的监控系统,同样可能会让之前在高可用设计方面所做的努力功亏一篑.一 ...

  5. MySQL性能调优与架构设计——第 15 章 可扩展性设计之Cache与Search的利用

    第 15 章 可扩展性设计之Cache与Search的利用 前言: 前面章节部分所分析的可扩展架构方案,基本上都是围绕在数据库自身来进行的,这样是否会使我们在寻求扩展性之路的思维受到“禁锢”,无法更为 ...

  6. MySQL性能调优与架构设计——第13章 可扩展性设计之 MySQL Replication

    第13章 可扩展性设计之 MySQL Replication 前言: MySQL Replication 是 MySQL 非常有特色的一个功能,他能够将一个 MySQL Server 的 Instan ...

  7. MySQL性能调优与架构设计——第11章 常用存储引擎优化

    第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...

  8. MySQL性能调优与架构设计——第6章 MySQL Server 性能的相关因素

    第6章 MySQL Server 性能的相关因素 前言 大部分人都一致认为一个数据库应用系统(这里的数据库应用系统概指所有使用数据库的系统)的性能瓶颈最容易出现在数据的操作方面,而数据库应用系统的大部 ...

  9. MySQL性能调优与架构设计——第3章 MySQL存储引擎简介

    第3章 MySQL存储引擎简介 3.1 MySQL 存储引擎概述 MyISAM存储引擎是MySQL默认的存储引擎,也是目前MySQL使用最为广泛的存储引擎之一.他的前身就是我们在MySQL发展历程中所 ...

随机推荐

  1. Volley学习小结

    1.概述 volley英文即是"齐射,并发",是谷歌在2013年推出的网络通信库,有如下特点: [1]通信更快,更简单 [2]Get.Post网络请求以及网络数据图像的高效的异步请 ...

  2. 02_创建Git仓库,克隆仓库,git add,git commit,git push,git pull,同行冲突,不同行冲突的结局方案,git mergetool的使用

    1 创建Git资源库,残酷目录信息 创建git资源库的命令: git init –bare 仓库名称 (其中-bare表示的意思是空的库的意思) 进入E:\software\repository\gi ...

  3. 线性表的顺序存储设计和实现 - API函数实现

    基本概念 设计与实现 插入元素算法 判断线性表是否合法 判断插入位置是否合法 把最后一个元素到插入位置的元素后移一个位置 将新元素插入 线性表长度加1 获取元素操作 判断线性表是否合法 判断位置是否合 ...

  4. 【一天一道LeetCode】#9. Palindrome Number

    一天一道LeetCode系列 (一)题目 Determine whether an integer is a palindrome. Do this without extra space. Some ...

  5. How Tomcat Works读书笔记三-------连接器

    几个概念 HttpServlet,Servlet Servlet是一个接口,定义了一种网络服务,我们所有的servlet都要实现它(或它的子类) HttpServlet是一个抽象类,它针对的就是htt ...

  6. 可靠联机的 TCP 协议

    可靠联机的 TCP 协议 在前面的 OSI 七层协议当中,在网络层的 IP 之上则是传送层,而传送层的数据打包成什么? 最常见的就是 TCP 封包了.这个 TCP 封包数据必须要能够放到 IP 的数据 ...

  7. PS 图像特效算法— —渐变

    这个特效利用图层的混合原理,先设置一个遮罩层,然后用遮罩层与原图进行相乘,遮罩层不同,图像最后呈现的渐变效果也不一样. clc;clear all;close all;addpath('E:\Phot ...

  8. linux内核自旋锁API

    我们大概都了解,锁这种机制其实是为了保护临界区代码的,关于使用和定义,我总结的API如下: #include <linux/spinlock.h> 定义自旋锁 spinlock_t loc ...

  9. GetMemory那一题的理解

    #include "stdafx.h" #include <iostream> void GetMemory(char *p,int num) { p = (char* ...

  10. 详谈linux中压缩

    1.压 缩 的 用 途 和 技 术 1.1 为什么需要压缩: ①你是否有过文件档案太大,导致无法以正常的email方式发送出去(很多email都有容量大约25MB每封信的限制啊!)? ②你是否有过要备 ...