来源:oracleace
关于号主,姚远:
Oracle ACE(Oracle和MySQL数据库方向)
华为云最有价值专家
《MySQL 8.0运维与优化》的作者
拥有 Oracle 10g、12c和19c OCM等数十项数据库认证
曾任IBM公司数据库部门经理
20+年DBA经验,服务2万+客户
精通C和Java,发明两项计算机专利
5.7版本中查询锁竞争
在MySQL 8.0 之前,必须SET GLOBAL innodb_status_output_locks=ON后才能在SHOW ENGINE INNODB STATUS中查到数据锁,例如下面这个事务:
mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> select * from t1 where intcol1=0 for update;...900 rows in set (0.00 sec)
在SHOW ENGINE INNODB STATUS中查到
---TRANSACTION 7827, ACTIVE 11 sec222 lock struct(s), heap size 24784, 5720 row lock(s)MySQL thread id 9912, OS thread handle 139967683151616, query id 11123 localhost rootTABLE LOCK table `mysqlslap`.`t1` trx id 7827 lock mode IXRECORD LOCKS space id 25 page no 37 n bits 1056 index in_1 of table `mysqlslap`.`t1` trx id 7827 lock_mode X...
修改了900行,却锁住了5720行。查询space id为25对应的对象:
mysql> select * from information_schema.INNODB_SYS_DATAFILES where space=25;+-------+--------------------+| SPACE | PATH |+-------+--------------------+| 25 | ./mysqlslap/t1.ibd |+-------+--------------------+1 row in set (0.00 sec)
在另外一个session里执行
mysql> update t1 set intcol1=1 where intcol1=0;ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
查询锁的情况
mysql> select * from information_schema.innodb_lock_waits;+-------------------+-------------------+-----------------+------------------+| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |+-------------------+-------------------+-----------------+------------------+| 7829 | 7829:25:4:2 | 7827 | 7827:25:4:2 |+-------------------+-------------------+-----------------+------------------+1 row in set, 1 warning (0.00 sec)mysql> select * from information_schema.innodb_locks;+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+| 7829:25:4:2 | 7829 | X | RECORD | `mysqlslap`.`t1` | GEN_CLUST_INDEX | 25 | 4 | 2 | 0x000000000200 || 7827:25:4:2 | 7827 | X | RECORD | `mysqlslap`.`t1` | GEN_CLUST_INDEX | 25 | 4 | 2 | 0x000000000200 |+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+2 rows in set, 1 warning (0.00 sec)
查询阻塞的线程:
SELECT b.trx_mysql_thread_id AS 'blocked_thread_id',b.trx_query AS 'blocked_sql_text',c.trx_mysql_thread_id AS 'blocker_thread_id',c.trx_query AS 'blocker_sql_text',( Unix_timestamp() - Unix_timestamp(c.trx_started) )AS 'blocked_time'FROM information_schema.innodb_lock_waits aINNER JOIN information_schema.innodb_trx bON a.requesting_trx_id = b.trx_idINNER JOIN information_schema.innodb_trx cON a.blocking_trx_id = c.trx_idWHERE ( Unix_timestamp() - Unix_timestamp(c.trx_started) ) > 4;+-------------------+-----------------------------------------+-------------------+------------------+--------------+| blocked_thread_id | blocked_sql_text | blocker_thread_id | blocker_sql_text | blocked_time |+-------------------+-----------------------------------------+-------------------+------------------+--------------+| 9921 | update t1 set intcol1=1 where intcol1=0 | 9917 | NULL | 782 |+-------------------+-----------------------------------------+-------------------+------------------+--------------+1 row in set, 1 warning (0.00 sec)
根据线程号查询执行的SQL
SELECT a.sql_text,c.id,d.trx_startedFROM performance_schema.events_statements_current ajoin performance_schema.threads bON a.thread_id = b.thread_idjoin information_schema.processlist cON b.processlist_id = c.idjoin information_schema.innodb_trx dON c.id = d.trx_mysql_thread_idwhere c.id=9917ORDER BY d.trx_started\G*************************** 1. row ***************************sql_text: select * from t1 where intcol1=0 for updateid: 9917trx_started: 2023-05-26 13:24:591 row in set (0.00 sec)
解决锁竞争
mysql> create index in_1 on t1(intcol1);Query OK, 0 rows affected (0.04 sec)Records: 0 Duplicates: 0 Warnings: 0mysql> show create table t1\G*************************** 1. row ***************************Table: t1Create Table: CREATE TABLE `t1` (`intcol1` int(32) DEFAULT NULL,`intcol2` int(32) DEFAULT NULL,`charcol1` varchar(128) DEFAULT NULL,`charcol2` varchar(128) DEFAULT NULL,`charcol3` varchar(128) DEFAULT NULL,KEY `in_1` (`intcol1`)) ENGINE=InnoDB DEFAULT CHARSET=latin11 row in set (0.00 sec)
再锁住同样的行
mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> select * from t1 where intcol1=0 for update;...900 rows in set (0.00 sec)
在SHOW ENGINE INNODB STATUS中查到
---TRANSACTION 7841, ACTIVE 15 sec155 lock struct(s), heap size 24784, 1801 row lock(s)MySQL thread id 9917, OS thread handle 139966608627456, query id 11227 localhost rootTABLE LOCK table `mysqlslap`.`t1` trx id 7841 lock mode IXRECORD LOCKS space id 25 page no 37 n bits 1056 index in_1 of table `mysqlslap`.`t1` trx id 7841 lock_mode X...
被锁住的记录从之前的5720条减少到1801条。
有索引后执行计划也不同,加索引之前的执行计划
mysql> explain select * from t1 where intcol1=0 for update;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 6143 | 10.00 | Using where |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+1 row in set, 1 warning (0.00 sec)
加了索引后的执行计划是:
mysql> explain select * from t1 where intcol1=0 for update;+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+| 1 | SIMPLE | t1 | NULL | ref | in_1 | in_1 | 5 | const | 900 | 100.00 | NULL |+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+1 row in set, 1 warning (0.00 sec)
8.0版本
