笔记记录自林晓斌(丁奇)老师的《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. php基础-cookie&session

    设置cookie //设置cookie setcookie('key', 'value', time() + 60, '/'); 设置session //必须开启session session_sta ...

  2. Nginx服务器 配置 https

    参考 这里 1. 购买证书 2. 补全信息 3. 下载证书( .pem + .key ) 4. 上传至服务器  /usr/local/nginx/conf/cert 下 5. 修改 nginx.con ...

  3. MySql解除安全模式:Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

    在修改一条数据字段时报错: Error Code: 1175. You are using safe update mode and you tried to update a table witho ...

  4. 简单工厂模式demo

    1. 简单工厂模式 domain的接口 public interface Color{ public void display(); } red public Class Red implements ...

  5. FCC(ES6写法) Make a Person

    用下面给定的方法构造一个对象. 方法有 getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(l ...

  6. libguestfs手册(3): virt命令

    guestmount root# guestmount -a ubuntutest1.img -m /dev/sda1 ubuntutestp1 root# cd ubuntutestp1/root: ...

  7. web项目 easyui-datagrid开发实践

    一,引言 工作的需要,做了3年的wpf(mvvm)……,又因为项目的需求,回归到web的开发. ■  3 years ago,vue是我三年前没用过的玩意儿. ■  3 years ago,boots ...

  8. [Swift]LeetCode1002. 查找常用字符 | Find Common Characters

    Given an array A of strings made only from lowercase letters, return a list of all characters that s ...

  9. 初步学习大数据——设置虚拟机固定ip地址

    1.打开本机的网络连接 2.右键以太网,打开属性. 3.右键VMnet8,打开属性.最多不能超过255,最少不能小于0.    0~255之间. 4.找到你要设置固定IP地址的虚拟机 ,选择上方的编辑 ...

  10. 4.Git基础-查看提交历史

    1.查看提交历史 --  git log  使用 git log 可以查看到所有的提交(commit)历史. 1. $ git log 列出所有commit,最新的commit在最上面.会显示每个提交 ...