본문 바로가기

Database/MySQL

MySQL Lock

metadata lock 

metadata lock 은 dql, dml, ddl 들의 조합에서 발생하는 테이블의 구조변경 시도에 따른 lock 이다.

session 1) metadata lock 발생

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
 
mysql> drop table t1;
Query OK, 0 rows affected (0.02 sec)
 
mysql> create table t1(i1 int primary key,i2 int );
insert into t1 values( 1,1 );
Query OK, 0 rows affected (0.03 sec)
 
mysql> insert into t1 values( 1,1 );
commit;
Query OK, 1 row affected (0.01 sec)
 
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
 
mysql>
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from t1 ;
+----+------+
| i1 | i2   |
+----+------+
|  1 |    1 |
+----+------+
1 row in set (0.00 sec)

session 2) metadata lock waiting

mysql> alter table t1 add column i3 int;

session 3) metadata lock 확인

-- Waiting for table metadata lock 은 누군가에 의해 발생한 metadata lock 으로 인해
-- waiting 이 발생했다는 것이다.
mysql> show processlist;
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
| Id | User     | Host            | db   | Command          | Time | State                                                         | Info                             | Rows_sent | Rows_examined |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
|  7 | proxysql | 10.1.5.31:57248 | NULL | Sleep            |    7 |                                                               | NULL                             |         0 |             0 |
|  8 | repl     | 10.1.5.24:48320 | NULL | Binlog Dump GTID |  675 | Master has sent all binlog to slave; waiting for more updates | NULL                             |         0 |             0 |
|  9 | root     | localhost       | NULL | Query            |    0 | starting                                                      | show processlist                 |         0 |             0 |
| 10 | bos      | localhost       | test | Query            |  125 | Waiting for table metadata lock                               | alter table t1 add column i3 int |         0 |             0 |
| 12 | bos      | localhost       | test | Sleep            |  131 |                                                               | NULL                             |         1 |             1 |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
5 rows in set (0.00 sec)
 
 
-- processlist_id 12번이 조회를 하면서 SHARED_READ lock 을 유지하고 있기 때문에
-- ( auto commmit 이었다면 data fetch 후 lock 이 해제된다. )
-- 10번 의 alter 구문이 waiting 상태가 된다.
SELECT
    OBJECT_TYPE,
    OBJECT_SCHEMA,
    OBJECT_NAME,
    LOCK_TYPE,
    LOCK_STATUS,
    THREAD_ID,
    PROCESSLIST_ID,
    PROCESSLIST_INFO
FROM
    performance_schema.metadata_locks INNER JOIN performance_schema.threads
ON
    THREAD_ID = OWNER_THREAD_ID
WHERE
    PROCESSLIST_ID <> CONNECTION_ID() and
    OBJECT_SCHEMA = 'test'
;
+-------------+---------------+-------------+---------------------+-------------+-----------+----------------+----------------------------------+
| OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | LOCK_TYPE           | LOCK_STATUS | THREAD_ID | PROCESSLIST_ID | PROCESSLIST_INFO                 |
+-------------+---------------+-------------+---------------------+-------------+-----------+----------------+----------------------------------+
| TABLE       | test          | t1          | SHARED_READ         | GRANTED     |        64 |             12 | select * from t1                 |
| SCHEMA      | test          | NULL        | INTENTION_EXCLUSIVE | GRANTED     |        62 |             10 | alter table t1 add column i3 int |
| TABLE       | test          | t1          | SHARED_UPGRADABLE   | GRANTED     |        62 |             10 | alter table t1 add column i3 int |
| TABLE       | test          | #sql-313d_a | EXCLUSIVE           | GRANTED     |        62 |             10 | alter table t1 add column i3 int |
| TABLE       | test          | t1          | EXCLUSIVE           | PENDING     |        62 |             10 | alter table t1 add column i3 int |
+-------------+---------------+-------------+---------------------+-------------+-----------+----------------+----------------------------------+

session 3 ) metadata lock 해결

-- 1) 12번에서 commmit; 하기
-- 2) 10번에서 alter 를 취소하기
-- 3) 12번 connection 을 강제로 kill하기
 
 
-- session 3
mysql> kill 12;
Query OK, 0 rows affected (0.00 sec)
 
 
mysql> show processlist;
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
| Id | User     | Host            | db   | Command          | Time | State                                                         | Info             | Rows_sent | Rows_examined |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
|  7 | proxysql | 10.1.5.31:57248 | NULL | Sleep            |    9 |                                                               | NULL             |         0 |             0 |
|  8 | repl     | 10.1.5.24:48320 | NULL | Binlog Dump GTID | 1257 | Master has sent all binlog to slave; waiting for more updates | NULL             |         0 |             0 |
|  9 | root     | localhost       | NULL | Query            |    0 | starting                                                      | show processlist |         0 |             0 |
| 10 | bos      | localhost       | test | Sleep            |  707 |                                                               | NULL             |         0 |             0 |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
4 rows in set (0.00 sec)
 
 
-- session 2
mysql> alter table t1 add column i3 int;
Query OK, 0 rows affected (9 min 9.33 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
 
-- session 1
mysql> commit;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    37
Current database: test
 
Query OK, 0 rows affected (0.00 sec)
 
mysql>

 


data lock

data lock 은 테이블 전체 혹은 일부 row 에 대해 lock 을 하는 경우이다. 보통은 dml 에 의한 transaction 이 commit 되지 않은 상태에서 발생한다.

session 1) data lock  발생

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
 
mysql> drop table t1;
create table t1(i1 int primary key,i2 int );
Query OK, 0 rows affected (0.02 sec)
 
mysql> create table t1(i1 int primary key,i2 int );
insert into t1 values( 1,1 );
commit;
Query OK, 0 rows affected (0.03 sec)
 
mysql> insert into t1 values( 1,1 );
Query OK, 1 row affected (0.00 sec)
 
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
 
mysql>
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
 
mysql> update t1 set i2 = 2 where i1 =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
 
mysql>

session 2) data lock waiting

mysql> update t1 set i2 = 3 where i1 =1;
mysql> update t1 set i2 = 3 where i1 =1;

session 3) data lock 확인

-- 87 이 update 를 위해 wait 하고 있다.
mysql> show processlist;
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
| Id | User     | Host            | db   | Command          | Time | State                                                         | Info                             | Rows_sent | Rows_examined |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
|  7 | proxysql | 10.1.5.31:57248 | NULL | Sleep            |    7 |                                                               | NULL                             |         0 |             0 |
|  8 | repl     | 10.1.5.24:48320 | NULL | Binlog Dump GTID | 4235 | Master has sent all binlog to slave; waiting for more updates | NULL                             |         0 |             0 |
|  9 | root     | localhost       | NULL | Query            |    0 | starting                                                      | show processlist                 |         0 |             0 |
| 37 | bos      | localhost       | test | Sleep            |   39 |                                                               | NULL                             |         0 |             1 |
| 68 | root     | localhost       | NULL | Sleep            |   63 |                                                               | NULL                             |         0 |             0 |
| 87 | bos      | localhost       | test | Query            |   35 | updating                                                      | update t1 set i2 = 3 where i1 =1 |         0 |             0 |
+----+----------+-----------------+------+------------------+------+---------------------------------------------------------------+----------------------------------+-----------+---------------+
6 rows in set (0.00 sec)
 
 
 
 
-- 37번이 최초 lock 을 잡고 있고
-- 87번이 대기하고 있다.
select
    a.ROLE,
    a.PROCESSLIST_ID,
    a.PROCESSLIST_USER,
    a.PROCESSLIST_INFO,
    c.LOCK_TYPE,
    c.LOCK_MODE
from
    (select
        a.THREAD_ID,
        case
            when a.THREAD_ID = b.BLOCKING_THREAD_ID
            then 'GRANTER'
            when a.THREAD_ID = b.REQUESTING_THREAD_ID
            then 'REQUESTER'
            else 'UNKNOW'
        end as ROLE,
        a.PROCESSLIST_ID,
        a.PROCESSLIST_USER,
        a.PROCESSLIST_INFO
    from
        performance_schema.threads a,
        performance_schema.data_lock_waits b
    where
        a.THREAD_ID = b.BLOCKING_THREAD_ID or  a.THREAD_ID = b.REQUESTING_THREAD_ID
    ) a,
    performance_schema.data_locks c
where
    a.THREAD_ID = c.THREAD_ID
;
+-----------+----------------+------------------+----------------------------------+-----------+---------------+
| ROLE      | PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_INFO                 | LOCK_TYPE | LOCK_MODE     |
+-----------+----------------+------------------+----------------------------------+-----------+---------------+
| GRANTER   |             37 | bos              | update t1 set i2 = 2 where i1 =1 | TABLE     | IX            |
| GRANTER   |             37 | bos              | update t1 set i2 = 2 where i1 =1 | RECORD    | X,REC_NOT_GAP |
| REQUESTER |             87 | bos              | update t1 set i2 = 3 where i1 =1 | TABLE     | IX            |
| REQUESTER |             87 | bos              | update t1 set i2 = 3 where i1 =1 | RECORD    | X,REC_NOT_GAP |
+-----------+----------------+------------------+----------------------------------+-----------+---------------+
4 rows in set (0.00 sec)

session 3) data lock 해결

-- 1) 10번에서 commmit; 하기
-- 2) 12번에서 update 를 취소하기
-- 3) 10번 connection 을 강제로 kill하기
 
 
-- session 2)
mysql> kill 37;
Query OK, 0 rows affected (0.00 sec)
 
 
-- session 1)
mysql> commit;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    102
Current database: test
 
Query OK, 0 rows affected (0.00 sec)
 
 
-- session 2)
mysql> update t1 set i2 = 3 where i1 =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

 

reference

'Database > MySQL' 카테고리의 다른 글

semi replication  (0) 2021.10.01
mysql admin script  (0) 2021.10.01
install mysql(percona) by tarball  (0) 2021.10.01
MySQL partition 관리  (0) 2021.10.01
InnoDB on-disk structures  (0) 2021.10.01