Ⅰ、 show engine innodb status\G

1.1 实力分析一波

锁介绍的那篇中已经提到了这个命令,现在我们开一个参数,更细致的分析一下这个命令

(root@localhost) [(none)]> set global innodb_status_output_locks=1;
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> delete from l where a = 2;
Query OK, 1 row affected (0.00 sec) (root@localhost) [test]> update l set b = b + 1 where a = 4;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0 (root@localhost) [test]> show engine innodb status\G
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 30217412, ACTIVE 37 sec
2 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2
MySQL thread id 355, OS thread handle 140483080300288, query id 1263 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 30217412 lock mode IX
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217412 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd14c4; asc ;;
2: len 7; hex 2400000fc21499; asc $ ;;
3: len 4; hex 80000004; asc ;;
4: len 4; hex 80000006; asc ;;
5: len 4; hex 80000008; asc ;; Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80000004; asc ;;
1: len 6; hex 000001cd14c4; asc ;;
2: len 7; hex 2400000fc214c8; asc $ ;;
3: len 4; hex 80000007; asc ;;
4: len 4; hex 80000008; asc ;;
5: len 4; hex 8000000a; asc ;;
...

解析:

  • table lock IX 意向排他锁(意向锁都是表锁)
  • record locks 记录锁

    -->space id 表空间

    -->page no 第几个页,所有的记录开始写都是从表的第四个页开始写,第四个页也是聚集索引的root page

    -->index PRIMARY 表示在主键上加了一把锁

    -->lock_mode 锁的模式

    -->locks rec but not gap 这个先不看

    -->heap no 2 PHYSICAL RECORD: n_fields 6 锁住记录的heap no为2的物理记录,这个记录一共6个列

    -->compact format 这条记录的存储格式是compact(dynamic也是compact)

    -->info bits 0表示这条记录没有被删除;非0表示被修改或者被删除(32)

Q? 表中是四个列,为什么这把是6个列?

  • 如果没有主键的话,会多一个隐藏列row_id,这里有主键row_id就是主键那不谈
  • 6个字节的表示事务id,7个字节表示回滚指针,这两个列就是隐藏列

1.2、趁热打铁,分析一下等待的情况

session1:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> delete from l where a = 2;
Query OK, 1 row affected (0.00 sec)

session2:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where a=2 for update;
hang住了

session3:

...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421958478909040, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 30217455, ACTIVE 1741 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 396, OS thread handle 140483215816448, query id 2340 localhost root statistics
select * from l where a=2 for update
------- TRX HAS BEEN WAITING 27 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217455 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd14ee; asc ;;
2: len 7; hex 230000013d27d5; asc # =' ;;
3: len 4; hex 80000004; asc ;;
4: len 4; hex 80000006; asc ;;
5: len 4; hex 80000008; asc ;; ------------------
TABLE LOCK table `test`.`l` trx id 30217455 lock mode IX
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217455 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd14ee; asc ;;
2: len 7; hex 230000013d27d5; asc # =' ;;
3: len 4; hex 80000004; asc ;;
4: len 4; hex 80000006; asc ;;
5: len 4; hex 80000008; asc ;; ---TRANSACTION 30217454, ACTIVE 1821 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 355, OS thread handle 140483080300288, query id 2339 localhost root
TABLE LOCK table `test`.`l` trx id 30217454 lock mode IX
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217454 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd14ee; asc ;;
2: len 7; hex 230000013d27d5; asc # =' ;;
3: len 4; hex 80000004; asc ;;
4: len 4; hex 80000006; asc ;;
5: len 4; hex 80000008; asc ;;
...
  • 找到LOCK WAIT

    LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s) 两个锁结构,一个记录锁
  • 找到TRX HAS BEEN WAITING 27 SEC FOR THIS LOCK TO BE GRANTED

    等的是主键是2的这条记录上的锁,锁的类型是排他锁
  • 再往下看,找到hold住2这条记录的事务,根据thread id 355可以找到对应的线程

    这个355就是show processlist;对应的id,我们去session1上看下便知
    (root@localhost) [test]> show processlist;
+-----+------+-----------+------+---------+------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+------+-----------+------+---------+------+----------+------------------+
| 355 | root | localhost | test | Query | 0 | starting | show processlist |
| 396 | root | localhost | test | Sleep | 1321 | | NULL |
+-----+------+-----------+------+---------+------+----------+------------------+
2 rows in set (0.00 sec) 注意再thread_id表中就不一样了,是对应proceelist_id
(root@localhost) [test]> select thread_id,processlist_id,thread_os_id from performance_schema.threads where processlist_id is not NULL;
+-----------+----------------+--------------+
| thread_id | processlist_id | thread_os_id |
+-----------+----------------+--------------+
| 27 | 1 | 10574 |
| 381 | 355 | 18745 |
| 422 | 396 | 10592 |
+-----------+----------------+--------------+
3 rows in set (0.00 sec)
分别表示内部线程号(自增的),对应show processlist里的id,进程号

Ⅱ、简单点,上面是不是太专业了

2.1 利用三张表写一个sql脚本

重复之前的步骤,一边开一个事务删除2这条记录不提交,另一边用for update查2这条记录
(root@localhost) [(none)]> SELECT
-> r.trx_id waiting_trx_id,
-> r.trx_mysql_thread_id waiting_thread,
-> r.trx_query wating_query,
-> b.trx_id blocking_trx_id,
-> b.trx_mysql_thread_id blocking_thread,
-> b.trx_query blocking_query
-> FROM
-> information_schema.innodb_lock_waits w
-> INNER JOIN
-> information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
-> INNER JOIN
-> information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
+----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+
| waiting_trx_id | waiting_thread | wating_query | blocking_trx_id | blocking_thread | blocking_query |
+----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+
| 30217455 | 396 | select * from l where a=2 for update | 30217454 | 355 | NULL |
+----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+
1 row in set, 1 warning (0.02 sec)

2.2 走sys库看一把,更简单

5.7才有sys库,不过5.6也可以自行把sys库弄进去

(root@localhost) [(none)]> select * from sys.innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2018-06-03 00:52:01
wait_age: 00:00:14
wait_age_secs: 14
locked_table: `test`.`l`
locked_index: PRIMARY
locked_type: RECORD
waiting_trx_id: 30217455
waiting_trx_started: 2018-06-03 00:11:13
waiting_trx_age: 00:41:02
waiting_trx_rows_locked: 5
waiting_trx_rows_modified: 0
waiting_pid: 396
waiting_query: select * from l where a=2 for update
waiting_lock_id: 30217455:1358:3:2
waiting_lock_mode: X
blocking_trx_id: 30217454
blocking_pid: 355
blocking_query: NULL
blocking_lock_id: 30217454:1358:3:2
blocking_lock_mode: X
blocking_trx_started: 2018-06-03 00:09:53
blocking_trx_age: 00:42:22
blocking_trx_rows_locked: 1
blocking_trx_rows_modified: 1
sql_kill_blocking_query: KILL QUERY 355
sql_kill_blocking_connection: KILL 355
1 row in set, 3 warnings (0.09 sec)

tips:

  • waiting_lock_id: 30217455:1358:3:2 这个东西表示 事务ID:space:page_No:heap_no,其他得比较简单不用说了
  • blocking_query是null,waiting_query是知道的,为什么?

    因为blocking的语句已经执行结束了,只是事务没提交罢了

    线上大部分时间是看不到这个blocking_query的

    即使show engine innodb status\G也是只能看到在等待哪条记录上的锁释放,而看不到是哪条sql导致的这个问题
  • 最下面的KILL QUERY和KILL的区别是?

    KILL QUERY是杀这个查询,KILL是直接杀连接

Ⅲ、锁超时

刚才模拟锁等待过程中出现了下面得报错

(root@localhost) [test]> select * from l where a=2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

这叫锁等待超时,开发人员通常把这个和死锁混为一谈

lock持有的时间是以事务为单位的,事务提交后才会把事务里所有的锁释放,这是无法避免的,不过可以通过一个参数来控制超时时间

(root@localhost) [test]> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50 |
+--------------------------+-------+
1 row in set (0.00 sec)

默认50s,建议设置为3s左右即可

Ⅲ、强行分析heap no

innodb中页里面的记录是逻辑有序的

一个页中,第一条插入的记录heap no是2,后面插入的heap no递增,这样在堆中就是有序的了,但是记录之间又是逻辑有序的,通过指针连接

heap no表示插入时的顺序,用来表示一个page中的record是什么时候插入的,所以加锁的定位是space->page_no->heap_no

一个page中,一条记录都没有,innodb默认会生成两条虚拟伪记录,min和max,min的heap_no是0,max的heap_no是1,所以用户插入的记录heap_no都是从2开始

max上是可以加锁的,min上面通常不加锁

Ⅳ、InnoDB中锁的管理

  • 每个事务每个page(不是每条记录)有一个锁的对象,通过位图(lock bitmap )的方式来管理,位图是基于每个page的

    page里面哪条record加锁了,就会把这条record的heap_no设置为1,heap_no就表示一个位图,表示第几位,所以innodb的锁是占用内存的,但是不是一个锁一个锁来管理锁的存储的(mysql上一个page的锁差不多30个字节就够了,网上都说的是100)
  • 没有锁升级(like oracle)

    sqlserver有锁升级,sqlserver是每个锁一个锁对象,innodb是每个page一个锁对象,所以锁的空间占用上,oracle<mysql<sqlserver

补充sqlserver和innodb全表更新对比

sqlserver每个记录一个锁对象

如果占用10字节,300w个page,每个page100条记录

InnoDB:300M(300w*100/1000/1000)

sqlserver:3G(300w10010/1000/1000)

tips:

  • sqlserver锁升级

    一个事务持有5000(默认)行锁升级到表锁,锁升级也不是一点都不好,毕竟内存变小了

InnoDB中锁的查看的更多相关文章

  1. InnoDB中锁的模式,锁的查看,算法

    InnoDB中锁的模式   Ⅰ.总览 S行级共享锁lock in share mode X行级排它锁增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X ...

  2. InnoDB中锁的模式

    Ⅰ.总览 S行级共享锁 lock in share mode X行级排它锁 增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X × × × × IX × ...

  3. InnoDB中锁的算法(1)

    Ⅰ.InnoDB锁算法的介绍 首先明确一点,锁锁住的是什么?锁锁住的是索引 Record Lock 单个行记录上的锁 Gap Lock 锁定一个范围,但不包含记录本身 Next-key Lock Ga ...

  4. InnoDB中锁的算法(2)

    Ⅰ.上节回顾 session1: (root@localhost) [test]> select * from l; +---+------+------+------+ | a | b | c ...

  5. InnoDB中锁的算法(3)

    Ⅰ.隐式锁vs显示锁 session1: (root@localhost) [test]> show variables like 'tx_isolation'; +-------------- ...

  6. Innodb中怎么查看锁信息

    一.前言 上一篇说了下innodb中锁的大概意思, 这篇说说怎么查看加的哪些锁.不然后续出现死锁或者锁等待都不知道为什么. 二.底层基础表信息 在学会如何查看有哪些锁信息时, 需要了解一些基础表信息, ...

  7. InnoDB之锁机制

    前两天听了姜老大关于InnoDB中锁的相关培训,刚好也在看这方面的知识,就顺便利用时间把这部分知识做个整理,方便自己理解.主要分为下面几个部分 1. InnoDB同步机制 InnoDB存储引擎有两种同 ...

  8. MySQL/InnoDB中,对于锁的认识

    MySQL/InnoDB的加锁,一直是一个面试中常问的话题.例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?我在工作过程中,也会经常用到,乐观锁,排它锁,等.于是今天就对 ...

  9. InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)

    Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...

随机推荐

  1. java生成32的md5签名串

    import java.security.MessageDigest; import lombok.extern.slf4j.Slf4j; /** * 签名帮助类 * * @author yangzl ...

  2. unit3d 初次接触

    最近, 有朋友告我,他们做那个 vr 视频啥的,告我看后,感觉很好,故 ,就去网上搜索一下,了解如下: 1..unit 3d 是啥? Unity3D是一个跨平台的游戏引擎 是由Unity Techno ...

  3. CentOS 6.5 x64下查找依赖包,或用YUM安装

    查看某个命令YUM上的安装源 1)当某个命令不存时进行查询所依赖的包,如:pstree [root@localhost ~]# yum provides pstree 已加载插件:fastestmir ...

  4. MSSQL数据导出到MYSQL

    MSSQL数据导出到MYSQL 花了一天时间把MSSQL里的数据导出到MYSQL, 好麻烦,二个数据库都是阿里云买的云服务器. 先上阿里云控制面板,备份下MSSQL数据库,下载备份下来,在本地电脑上还 ...

  5. Mybatis(三) 映射文件详解

    前面说了全局配置文件中内容的详解,大家应该清楚了,现在来说说这映射文件,这章就对输入映射.输出映射.动态sql这几个知识点进行说明,其中高级映射(一对一,一对多,多对多映射)在下一章进行说明. 一.输 ...

  6. 试试SQLServer 2014的内存优化表

    SQL Server2014存储引擎:行存储引擎,列存储引擎,内存引擎 SQL Server 2014中的内存引擎(代号为Hekaton)将OLTP提升到了新的高度. 现在,存储引擎已整合进当前的数据 ...

  7. 【iCore4 双核心板_ARM】例程二十九:SD_IAP_FPGA实验——更新升级FPGA

    实验现象及操作说明: 1.烧写程序成功,绿色ARM·LED灯点亮,三色FPGA·LED灯循环点亮,烧写失败,如果挂载SD卡失败,红灯快闪,如果打开文件失败,蓝灯快闪,读取文件指针移动失败,白灯点亮,升 ...

  8. Hibernate获取数据java.lang.StackOverflowError

    原因:因为在重写toString()方法时,把关联的属性也放入到toString方法中了,去掉就可以了. 如:重写的toString方法中不能有关联关系IDCard属性idCard public cl ...

  9. linux下启动和关闭tomcat服务的方式

    Linux下tomcat服务的启动.关闭与错误跟踪,通常通过以下几种方式启动关闭tomcat服务: 切换到tomcat主目录下的bin目录 启动tomcat服务 生产模式: 方式一:直接启动 ./st ...

  10. Direct3D 11 Tutorial 6:Lighting_Direct3D 11 教程6:灯光

    概述 在之前的教程中,世界看起来很无聊,因为所有对象都以相同的方式点亮. 本教程将介绍简单照明的概念及其应用方法. 使用的技术将是朗伯照明. 本教程的结果将修改前面的示例以包含光源. 该光源将附在轨道 ...