笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》

7) --行锁功能:怎么减少行锁对性能的影响?

  MySQL的行锁是在引擎层由各个引擎自己实现的。因此,并不是所有的引擎都支持行锁,如MyISAM引擎就不支持行锁。对于不支持行锁的引擎,只能使用表锁来进行并发控制。对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB是支持行锁的,这也是MyISAM被它替代的一个重要原因。

  顾名思义,行锁就是针对数据表中行记录的锁。比如事务A要更新某一行,同时事务B也要更新这一行,则B必须等待A的操作完成后才能进行更新。

两阶段锁协议:

  在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。因此,如果你的事务中需要锁多个行,要把最可能造成锁冲突,最可能影响并发度的锁尽量往后放。

  举一个具体的例子:

  客户A要在电影院B购买电影票,这可能涉及三个操作:

  1. 在A的账户余额中扣除电影票的票价
  2. 在影院B的余额中增加这张电影票的票价
  3. 记录一条交易记录。

  当然为了保证交易的原子性,我们要把这三个操作放在同一个事务中。那么你应该怎样安排上面的语句呢?(两条Update,一条Insert)。根据两阶段锁协议,不管你怎样安排顺序,所有的锁都是在需要时加上,事务提交时释放。因此,如果你把更新影院B余额的操作放在最后,那么影院余额这一行的锁的时间就最少,最大程度地减少了事务直接的锁等待,提升了并发度。

死锁和死锁检测:

  当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致几个线程都在进入无限等待的状态,称为死锁。当出现死锁后我们有两种策略:

  • 直接进入等待,直到超时,这个超时时间可以通过参数innodb_lock_wait_timeout来设置。
  • 另一种策略是,发起死锁监测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。

  第一种策略的默认值是50s,显然在生产环境这个值是无法接受的。但如果你把这个值设置的很小,如1s,当出现死锁时确实可以很快解开,但也会出现很多误伤。因此我们常采用第二种策略:主动死锁检测。并且,innodb_deadlock_detect的默认值本身就是on。主动死锁检测在发生死锁的时候能够快速发现并进行处理,但是它也有额外负担。例如有1000个线程并发更新同一行,那么死锁检测会这样工作,这1000个线程每个的事务被锁的时候都要去看一下它所依赖的线程有没有被别人锁住,如此循环来判断是否出现了循环等待。那么此时死锁检测的就会消耗大量CPU资源,你就会看到CPU利用率很高,但是每秒执行不了几个事务。

  那么怎么解决这种热点行更新导致的性能问题呢?问题的根源在于,死锁检测要耗费大量的CPU资源。一种治标的方式是,如果你能确保事务一定不会出现死锁,可以临时把死锁检测关掉。当然这个操作伴随着一定的风险,另一个思路是控制并发度。根据上面的分析,你会发现如果并发能够控制住,比如同一行在同一时间最多只有10个线程在更新,那么死锁检测的成本就是可以接受的。当然你也可以从设计上来优化这里的逻辑。

上篇问题:

  备份一般都会在备库上执行,你在用-single-transaction方法做逻辑备份的过程中,如果主库上的一个小表做了一个DDL,比如给一个表上加了一列。这时候,从备库上会看到什么现象呢?

  (DML: Data manipulation language,数据操纵语言,增删改查等;DDL:Data definition language,数据库定义语言,修改表结构等;DCL:Data control language数据库控制语言,修改用户权限等)

  假设这个DDL是针对表t1的,这里把备份过程中几个关键的语句列出来:

Q1:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Q2:START TRANSACTION WITH CONSISTENT SNAPSHOT;
/* other tables */
Q3:SAVEPOINT sp;
/* 时刻 1 */
Q4:show create table `t1`;
/* 时刻 2 */
Q5:SELECT * FROM `t1`;
/* 时刻 3 */
Q6:ROLLBACK TO SAVEPOINT sp;
/* 时刻 4 */
/* other tables */

  在备份开始的时候,为了确保可重复读隔离级别,再设置一次隔离级别(Q1时刻)。启动事务,使用with consistent snapshot确保这个语句执行完成后就可以得到一个一致性视图。(Q2时刻)设置一个保存点.(Q3时刻)。拿到t1的表结构(Q4时刻)。正式导数据(Q5时刻)。回滚到SAVEPOINT sp,在这里的作用是释放t1的MDL锁。

我们题目设定中t1是小表,假定DDL到达后如果开始执行则很快就能执行完成。

参考答案如下:

  1. 如果在Q4语句执行之前主库的DDL到达,现象:没有影响,备份拿到的是DDL后的表结构。
  2. 如果在‘时刻2’到达,则表结构被改过,Q5执行的时候,报Table defination has changed,please retry transaction,现象mysqldump终止。
  3. 如果在“时刻2”和“时刻3”之间到达,mysqldump占着t1的MDL读锁,binlog被阻塞,现象:主从延迟,直到Q6执行完成。
  4. 从“时刻4”开始,mysqldump释放了MDL读锁,现象:没有影响,备份拿到的是DDL之前的表结构。

问题:

  如果你要删除一个表里面的10000行数据,有以下三种方式:

  1. 直接执行 delete from T limit 10000;
  2. 在一个连接中循环执行20次delete from T limit 500;
  3. 在20个连接中同时执行delete from T limilt 500;

  你会选择哪种方式,为什么呢?

  

MySQL 笔记整理(7) --行锁功能:怎么减少行锁对性能的影响?的更多相关文章

  1. 最全mysql笔记整理

    mysql笔记整理 作者:python技术人 博客:https://www.cnblogs.com/lpdeboke Windows服务 -- 启动MySQL net start mysql -- 创 ...

  2. MySQL 笔记整理(6) --全局锁和表锁:给表加个字段怎么有这么多阻碍

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 6) --全局锁和表锁:给表加个字段怎么有这么多阻碍 数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候, ...

  3. MySQL 笔记整理(1) --基础架构,一条SQL查询语句如何执行

    最近在学习林晓斌(丁奇)老师的<MySQL实战45讲>,受益匪浅,做一些笔记整理一下,帮助学习.如果有小伙伴感兴趣的话推荐原版课程,很不错. 1) --基础架构,一条SQL查询语句如何执行 ...

  4. MySQL 笔记整理(20) --幻读是什么,幻读有什么问题?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 20) --幻读是什么,幻读有什么问题? 我们先来看看表结构和初始化数据 ...

  5. MySQL 笔记整理(9) --普通索引和唯一索引,应该怎么选择?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 9) --普通索引和唯一索引,应该怎么选择? 假如你在维护一个市民系统, ...

  6. MySQL 笔记整理(16) --“order by”是怎么工作的?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 16) --“order by”是怎么工作的? 在林老师的课程中,第15 ...

  7. MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 19) --为什么我只查一行的语句,也执行这么慢? 需要说明一下,如果M ...

  8. MySQL 笔记整理(18) --为什么这些SQL语句逻辑相同,性能却差异巨大?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 18) --为什么这些SQL语句逻辑相同,性能却差异巨大? 本篇我们以三 ...

  9. MySQL 笔记整理(13) --为什么数据表删掉一半,表文件大小不变?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 13) --为什么数据表删掉一半,表文件大小不变? 我们还是以MySQL ...

随机推荐

  1. 201771010118 马昕璐 《面向对象设计 java》第十七周实验总结

    1.实验目的与要求 (1) 掌握线程同步的概念及实现技术: (2) 线程综合编程练习 2.实验内容和步骤 实验1:测试程序并进行代码注释. 测试程序1: l 在Elipse环境下调试教材651页程序1 ...

  2. git如何避免push/pull时输入密码

    今天在搭建git服务器的时候,一切顺利,但是就是在git push的时候老是要输入密码,太烦了,然后百度搜索了一下,总结了主要有如下三种方法: 方法1 git config --global cred ...

  3. Linux shell编程-退出的状态码

    linux 提供了一个专门的变量$?来保存上个已执行命令的状态码 linux 的错误状态退出状态码没有什么标准可遵循,但有一些参考 状态码 描述 0 命令成功结束 1 一般性未知错误 2 不适合的sh ...

  4. oracle中文乱码问题解决

    中文乱码问题解决:1.查看服务器端编码select userenv('language') from dual;我实际查到的结果为:AMERICAN_AMERICA.ZHS16GBK2.执行语句 se ...

  5. [VUE]object.defineProperty的基本使用

    1.object.defineProperty 给一个对象定义一个新的属性或者在修改一个对象现有的属性,并返回这个对象 语法: Object.defineProperty(参数1,参数2,参数3) 参 ...

  6. 为bootstrap+angularJs打造的表格代码生成器

    private void btnCreateCode_Click(object sender, EventArgs e) { string objName = txtObjName.Text; if ...

  7. 【从零开始搭建自己的.NET Core Api框架】(五)由浅入深详解CORS跨域机制并快速实现

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...

  8. [Swift]LeetCode40. 组合总和 II | Combination Sum II

    Given a collection of candidate numbers (candidates) and a target number (target), find all unique c ...

  9. [Swift]LeetCode500. 键盘行 | Keyboard Row

    Given a List of words, return the words that can be typed using letters of alphabet on only one row' ...

  10. [SQL]LeetCode595. 大的国家 | Big Countries

    SQL架构 Create table If Not Exists World (name varchar(), continent varchar(), area int, population in ...