Working around MySQL lock metadata
Working around MySQL lock metadata
January 16, 2023
There are multiple documents about innodb locks on MySQL 5.7:
- InnoDB locking
 - Locks Set by Different SQL Statements in InnoDB
 - Using InnoDB Transaction and Locking Information
 
Granularity of locks
There are 4 types of granularity of locks
- Shared lock
 - Exclusive lock
 - Intention shard lock
 - Intention exclusive lock
 
Types of locks
- Record locks
 - Gap locks
 - Next-Key locks
- the value in the index for the next-key lock indicates as “supreme” pseudo-record, which is not a real value
 
 - Insert Intention locks
 - AUTO-INC locks
- This is a table lock, and how to lock the table depending on the configuration of 
innodb_autoinc_lock_mode 
 - This is a table lock, and how to lock the table depending on the configuration of 
 
Lock tables
- information_schema.innodb_trx
 - information_schema.innodb_locks
 - information_schema.innodb_lock_waits
 
Use cases
Update queries without an index
Create a test table and insert a few records.
create database test;
use test;
create table test1(id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL);
insert into test1(name, created_at, updated_at) values('test', NOW(), NOW());
insert into test1(name, created_at, updated_at) values('test 2', NOW(), NOW());
insert into test1(name, created_at, updated_at) values('test 3', NOW(), NOW());
insert into test1(name, created_at, updated_at) values('test 4', NOW(), NOW());
select * from test1;Then the last selct result would be like:
+----+--------+---------------------+---------------------+
| id | name   | created_at          | updated_at          |
+----+--------+---------------------+---------------------+
|  1 | test   | 2023-01-17 02:02:35 | 2023-01-17 02:02:35 |
|  2 | test 2 | 2023-01-17 02:02:36 | 2023-01-17 02:02:36 |
|  3 | test 3 | 2023-01-17 02:02:38 | 2023-01-17 02:02:38 |
|  4 | test 4 | 2023-01-17 02:02:40 | 2023-01-17 02:02:40 |
+----+--------+---------------------+---------------------+
4 rows in set (0.01 sec)Checking what the lock results will be:
session A
BEGIN; update test1 set name = 'test 2 changed' where name = 'test 2';session B: This will be locked because of the query on session A.
insert into test1(name, created_at, updated_at) values('test 5', NOW(), NOW());
Then we can see lock information like followings:
mysql> select * from information_schema.innodb_locks \G
*************************** 1. row ***************************
    lock_id: 1814:24:3:1
lock_trx_id: 1814
  lock_mode: X
  lock_type: RECORD
 lock_table: `test`.`test1`
 lock_index: PRIMARY
 lock_space: 24
  lock_page: 3
   lock_rec: 1
  lock_data: supremum pseudo-record
*************************** 2. row ***************************
    lock_id: 1811:24:3:1
lock_trx_id: 1811
  lock_mode: X
  lock_type: RECORD
 lock_table: `test`.`test1`
 lock_index: PRIMARY
 lock_space: 24
  lock_page: 3
   lock_rec: 1
  lock_data: supremum pseudo-record
2 rows in set, 1 warning (0.00 sec)You can see lock_data is the supremum pseudo-record, which is not a real record created for next-key lock.
Other tables look like followings:
mysql> select * from information_schema.innodb_trx \G
*************************** 1. row ***************************
                    trx_id: 1814
                 trx_state: LOCK WAIT
               trx_started: 2023-01-17 02:24:59
     trx_requested_lock_id: 1814:24:3:1
          trx_wait_started: 2023-01-17 02:24:59
                trx_weight: 2
       trx_mysql_thread_id: 4
                 trx_query: insert into test1(name, created_at, updated_at) values('test 5', NOW(), NOW())
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
                    trx_id: 1811
                 trx_state: RUNNING
               trx_started: 2023-01-17 02:03:26
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 3
       trx_mysql_thread_id: 3
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 5
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
2 rows in set (0.00 sec)mysql> select * from information_schema.innodb_lock_waits \G
*************************** 1. row ***************************
requesting_trx_id: 1815
requested_lock_id: 1815:24:3:1
  blocking_trx_id: 1811
 blocking_lock_id: 1811:24:3:1
1 row in set, 1 warning (0.01 sec)Last updated on