DB & AWS Knowledge
MySQL / MariaDB Lock 종류 (InnoDB 기준) 본문
- 해당 페이지에서는 MySQL / MariaDB (InnoDB 기준) 의 Lock 유형과 특징을 기재한다.
( 출처 : https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html - 공식 DOC )
( 출처 : https://www.letmecompile.com/mysql-innodb-lock-deadlock/ - 다른분 개인 블로그)- InnoDB 는 row lock 개념을 사용하기 때문에 row 단위의 lock 을 사용 할 수 있다. 이를 통하여 사용 되는 기본 Lock 의 종류는 아래와 같다.
- Shared Lock ( s )
- Select 를 하기 위해 사용 되는 Lock. 즉, 변경이 아닌 조회를 위해서만 사용되는 Lock 이다. 축약어로 s 라 쓴다.
- 다른 트랜잭션들이 조회 용도로만 데이터에 접근 시, 이에 대한 접근을 허용하며 이 트랜잭션 또한 독자적인 shared lock 을 획득한다.
- Exclusive Lock ( x )
- 데이터 변경 (update, delete) 시에 사용되는 Lock. 축약어로 x 라 쓴다.
- 조회, 변경유형에 관계없이 다른 트랜잭션이 변경될 데이터에 접근하는 것을 모두 차단한다.
- isolation level 에 따라 다른 트랜잭션의 접근 허용 여부가 달라진다.
예를 들어, MySQL / MariaDB 의 기본 isolation level 인 repeatable read 에서는 exclusive lock 이 발생하는 row 에 대해서
조회만 하는 트랜잭션은 접근이 허용된다.
( snapshot 개념으로 조회시의 데이터 형상을 보존하여 해당 트랙잭션이 처음 읽었던 데이터의 형태를 지속적으로 조회 할 수 있기 때문, 이를 consistent read 라고 한다.)
- 데이터 변경 (update, delete) 시에 사용되는 Lock. 축약어로 x 라 쓴다.
- Intention Locks
- row 및 table 단위에 대한 multiple granularity locking (다중 단위 잠금) 을 구현하기 위해 도입된 개념이다.
- 어떤 트랜잭션이 지금 당장이 아닌 나중에 의도적으로 share 또는 exclusive lock 을 특정 row 에서 획득 할 것이라는 것을 내포하여 취득하는 lock 이다.
- intention shared lock ( IS ), intention exclusive lock ( IX ) 두가지가 있으며, table 단위의 lock 이다.
- MySQL / MariaDB 에서는
- SELECT ... LOCK IN SHARE MODE 로 intention shared lock ( IS ) 을
- SELECT ... FOR UPDATE 로 intention exclusive lock ( IX ) 을 취득한다. - 위의 shared lock, exclusive lock 이 복합 발생시에는 아래의 과정을 따른다.
- SELECT ... LOCK IN SHARE MODE 로 intention shared lock ( IS ) 이 특정 table 에서 잡힌다면, shared lock 이 다음 후속으로 잡힌다.
- SELECT ... FOR UPDATE 로 intention exclusive lock ( IX ) 이 특정 table 에서 잡힌다면, exclusive 이 다음 후속으로 잡힌다.
- row 및 table 단위에 대한 multiple granularity locking (다중 단위 잠금) 을 구현하기 위해 도입된 개념이다.
- 아래의 표와 같이 위의 Lock 은 서로간의 유형에 따라 충돌 혹은 호환이 발생한다.
- 충돌가능성이 있는 Lock 유형은 먼저 Lock 을 취득한 작업이 끝날때까지 후속 Lock 유형이 대기를 한다. 동시 충돌이 발생하면 Deadlock 이 발생
- Lock 이 발생 시, 이를 보여주는 SHOW ENGINE INNODB STATUS 및 기타 모니터링 내용은 아래와 같다.
- 충돌가능성이 있는 Lock 유형은 먼저 Lock 을 취득한 작업이 끝날때까지 후속 Lock 유형이 대기를 한다. 동시 충돌이 발생하면 Deadlock 이 발생
- Shared Lock ( s )
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
Lock 종류 / 호환여부 | X | IX | S | IS |
X | Conflict | Conflict | Conflict | Conflict |
IX | Conflict | Compatible | Conflict | Compatible |
S | Conflict | Conflict | Compatible | Compatible |
IS | Conflict | Compatible | Compatible | Compatible |
- 위의 기본 Lock 이외에 DB 내부 상황에 따라 적용되는 Lock 은 아래와 같다.
- Record Lock
- PK, Unique Index 등을 통한 Index 참조로 접근하는 데이터에 거는 Lock 이다.
- 예를 들면 아래와 같다.
- SELECT id FROM t WHERE id = 10 LOCK IN SHARE MODE 쿼리를 실행하면 id=10 인 레코드에 대해 S lock이 걸린다.
- SELECT id FROM t WHERE id = 10 FOR UPDATE 쿼리를 실행하면 id=10 인 레코드에 대해 X lock이 걸린다. - PK 등의 인덱스가 없는 테이블에서 위의 쿼리를 수행시에는 내부적으로 hidden 인덱스를 만든 후, 이를 통하여 Lock 을 수행한다.
- Lock 이 발생 시, 이를 보여주는 SHOW ENGINE INNODB STATUS 및 기타 모니터링 내용은 아래와 같다.
- PK, Unique Index 등을 통한 Index 참조로 접근하는 데이터에 거는 Lock 이다.
- Record Lock
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc 'O;;
2: len 7; hex b60000019d0110; asc ;;
-
- Gap Lock
- 단일 row 단위로 발생하는 위의 Record Lock 과는 다르게 범위로 묶어서 발생되는 Lock 이다.
- 지정하는 범위 이외에 인덱스에 걸린 첫 데이터의 앞과 마지막 데이터의 뒤의 범위에도 지정 할 수 있다.
- 이에 대한 작동구조의 예를 들면 아래와 같다.
- SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE; 를 수행 시, 이로인하여 발생하는 Gap Lock 으로 인하여 조건안에 있는 숫자를 기입 할 수 없다.
(15 를 기입시, 위의 범위내에 숫자이므로, 내부적으로 실제 15라는 데이터 유무에 상관없이 기입을 허용하지 않음.)
- 단일, 다중 인덱스, 인덱스가 없을시에도 적용이 가능하다. - Unique Index 같이 단일 값만 허용하는 인덱스를 사용시에는 Lock 은 발생하지 않는다. 말 그대로 유일 값만 허용하기 때문에, 이로 인한 범위 데이터가 중복될 가능성이 없기 때문이다.
예를 들어 id 컬럼에 unique index 가 걸려있는 상태에서 SELECT * FROM child WHERE id = 100; 라는 쿼리를 수행 시,
조건걸의 컬럼 데이터는 유일값만 허용되므로 다른 row 에 데이터를 영향을 미칠 가능성이 없으므로 Lock 이 발생하지 않는다. - 단, 위의 컬럼이 non-unique index 이거나 인덱스가 없을 시에는 Lock 이 발생한다. (중복값 기입, 변경이 허용되는 상태이기 때문)
- DB 에서 다중 Gap Lock 이 발생할 수 있도록 허용한다. 예를 들어 A 라는 트랜잭션에서 Gap S Lock 을 취득하고 B 라는 트랜잭션에서 Gap X Lock 을 취득 시, 이를 동시에 허용한다.
B에서 인덱스 내 데이터가 작업을 통해 변동 혹은 삭제가 되더라도, A에서 Lock 을 지속적으로 유지해서 외부 트랜잭션의 데이터 변동을 막아야 하기 때문이다. - Isolation Level 을 Read Committed 로 바꾸거나 innodb_locks_unsafe_for_binlog 파라미터를 적용 시, 처음 접근 하는 데이터에 대한 형상 보존을 할 필요가 없으므로 해당 Lock 은 발생하지 않고,
아래와 같은 영향을 미친다.
- DB가 특정 where 조건에 대해서 확인 후, 조건에 부합하지 않는 row 들에 대해서는 record lock 을 해소 시킨다.
- update 구문을 적용 할 시에는 semi-consistent read 라 하여 DB 는 가장 최근에 committed 된 버전의 데이터를 조회하여 update 대상을 확인한다.
(즉, consistent read 처럼 조회시점의 데이터를 무조건 반환해 주지 않는다.)
- 단일 row 단위로 발생하는 위의 Record Lock 과는 다르게 범위로 묶어서 발생되는 Lock 이다.
- Next-Key Lock
- 위의 Record Lock 과 Gap Lock 이 복합적으로 발생하는 조합 Lock 이다.
- 실제 DB 에서는 위의 조합이 순차적으로 잠금 및 해소가 이루어 진다. 예를 들어, 어떤 세션이 특정 Record 에 대한 S 혹은 X Lock 을 획득 후,
다른 세션은 그 특정 Record 가 포함된 Gap 에 있는 데이터를 바로 넣거나 변경 할 수 없다. - 예시로 위의 내용을 파악하면 아래와 같다.
- Isolation Level 이 Repeatable Read 인 상태에서는 phantom read 예방을 위해 인덱스 scan 을 하면서 해당 Lock 을 취득한다.
- Lock 이 발생 시, 이를 보여주는 SHOW ENGINE INNODB STATUS 및 기타 모니터링 내용은 아래와 같다.
- 위의 Record Lock 과 Gap Lock 이 복합적으로 발생하는 조합 Lock 이다.
- Gap Lock
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc;;
1: len 6; hex 00000000274f; asc'O;;
2: len 7; hex b60000019d0110; asc;;
- Insert Intention Lock
- Gap Lock 이 발생시, 해당 Gap 내의 변동이 있는 특정 데이터에 영향을 주지 않는 데이터를 기입 할 시에 획득 되는 Lock.
InnoDB 에서 다중 트랜잭션들이 조회 및 변경 대상 데이터에 영향을 주지 않는 데이터를 대기없이 기입 할 수 있도록 도입된 개념이다. - 예시를 들면 아래와 같다.
- Insert Intention Lock 이 적용 되지 않은 상태에서 pk 에 3 과 6 인 데이터가 있다고 가정하자. 이 때, A, B 트랜잭션이 각각 5, 4 의 데이터를 넣을 예정일 시,
A 가 먼저 데이터를 기입시에는 3~5 사이에 Gap Lock 이 발생한다. B는 이로 인하여 A 의 기입이 끝날때까지 대기 해야 한다.
- Insert Intention Lock 이 적용 된다면 A 가 기입 시, Gap Lock 이 아닌 Insert Intention Lock 이 적용되고 B 는 해당 범위내의 데이터들에 영향을 주지 않는
데이터를 기입하므로 기입이 허용되어 서로간의 충돌이 발생하지 않음.
- Gap Lock 이 발생시, 해당 Gap 내의 변동이 있는 특정 데이터에 영향을 주지 않는 데이터를 기입 할 시에 획득 되는 Lock.
- AUTO-INC Locks
- MySQL / MariaDB 에서 쓰이는 AUTO_INCREMENT 컬럼의 숫자 연속성을 보장하기 위해 사용 하는 Lock 이다
- 하나의 트랜잭션이 해당 컬럼내의 연속 숫자를 부여받기 위해서 해당 Lock 을 걸고, 이로 인하여 다른 트랜잭션들이 대기함으로써 순차적으로 연속 숫자를 부여 받도록 해준다.
- innodb_autoinc_lock_mode 파라미터를 통하여 트랜잭션 내 쿼리들에 대한 Auto-Inc Lock 적용 범위를 조절 할 수 있다.
- MySQL / MariaDB 에서 쓰이는 AUTO_INCREMENT 컬럼의 숫자 연속성을 보장하기 위해 사용 하는 Lock 이다
- Metadata Lock
- Metadata Lock 은 MySQL (Ver 5.5 이상), MariaDB (Ver 5.5 이상) 부터 도입 된 Lock 종류로써 DB 내 다중 트랜잭션 발생시,
오브젝트내의 데이터 정합성을 보존하기 위하여 이에 대한 처리가 완료될때까지 테이블, 스키마단위의 metadata 오브젝트들의 접근을 허용하지 않는 Lock 이다.
대상 오브젝트는 테이블 이외에 프로시저, 함수, 트리거, 스케쥴 이벤트 및 Lock Table 등의 명시적 명령어 까지 포함된다. - 트랜잭션이 다중으로 유입될 시 수행되는 트랜잭션에 하나씩 부여 된다. (즉, 동시에 부여 되지않는다.)
DML, DDL 에 따라 Lock 이 적용되는 과정이 아래와 같다,
- DML 은 일반적으로 쿼리에서 조회하는 테이블명의 정렬 순서로 Lock 순서를 정한다.
- DDL 또한 DML 과 유사하나 명시적으로 언급되는 테이블이외에 외래키로 인하여 묵시적으로 연결되는 테이블에 따라 Lock 획득 순서가 달라 질 수 있다. - Start Transaction 등으로 명확하게 끝나지않은 트랜젝션이 발생 시, 그 이후로 들어오는 DDL 의 수행을 대기시킨다. (Metadata Lock 의 목적에 부합)
아래의 예시로 확인 할 수 있다.
- 먼저 Start Transaction 을 수행해서 t 와 nt 구문에 select 를 수행 시킨다.
- Metadata Lock 은 MySQL (Ver 5.5 이상), MariaDB (Ver 5.5 이상) 부터 도입 된 Lock 종류로써 DB 내 다중 트랜잭션 발생시,
START TRANSACTION;
SELECT * FROM t;
SELECT * FROM nt;
- 위의 세션이 commit, rollback 을 수행하지 않은 상태이므로 아직 끝나지 않은 트랜잭션이다.
- 이 상황에서 아래의 DDL 구문들을 수행하면 앞의 트랜잭션이 먼저 획득한 lock 으로 인하여
DDL 구문들이 metadata lock 을 획득하지 못하고 대기 상태가 된다.
- autocommit 으로 자동 트랜잭션 종료처리를 시킨다면, 맨 마지막의 명시적 Lock 구문만 metadata lock 을
획득한다.
DROP TABLE t;
ALTER TABLE t ...;
DROP TABLE nt;
ALTER TABLE nt ...;
LOCK TABLE t ... WRITE;
- 위의 Select 구문이 실패해도 이에 대한 기록을 Bin log 및 시스템 Log 에 기록 해야 하므로, 이를 기록 중에
Lock 은 바로 풀리지 않는다.
- Prepare 구문을 통하여 변동되는 변수값만 처리되도록 하기 위해서, 본 구문의 실행 계획을 DB내에
보관하는 동안에도 해당 Lock 이 발생한다.
- 보통 show processlist 명령어로 확인 시, 아래와 같은 화면으로 (waiting for metadata lock) 어떤 세션이
metadata lock 을 대기 중 인지 확인 할 수 있다.
(출처: https://www.percona.com/blog/2016/12/28/quickly-troubleshooting-metadata-locks-mysql-5-7/)
- Metadata Lock 의 어려운 점은 트랜잭션이 WAS 로부터 쿼리나 프로시저 형식등으로 state 가 null 인 상태로 수행 될 시, Processlist 에서 잠금을 유발하는 쿼리나 트랜잭션을 볼 수 없다는 것이다.
- MySQL 에서 이를 확인 할 수 있는 방법은 각각 아래와 같다. (출처 https://dev.mysql.com/doc/refman/5.7/en/metadata-locks-table.html)
- [mysqld] performance-schema-instrument='wait/lock/metadata/sql/mdl=ON' 으로 파라미터를 조절
- UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; 실시간으로 view 를 킬수도 있다.
- 위의 두 방법중 하나를 통하여 Performance Schema 내 metadata_locks 테이블을 사용 할 수 있다.
- 아래와 같이 고도화를 하여 어떤 PID (세션) 가 다른 세션의 lock 을 유발하는지도 확인 할 수 있다. (출처: https://www.percona.com/blog/2016/12/28/quickly-troubleshooting-metadata-locks-mysql-5-7/)
- [mysqld] performance-schema-instrument='wait/lock/metadata/sql/mdl=ON' 으로 파라미터를 조절
## 탐지 프로시저 ##
USE test;
DROP PROCEDURE IF EXISTS procShowMetadataLockSummary;
delimiter //
CREATE PROCEDURE procShowMetadataLockSummary()
BEGIN
DECLARE table_schema VARCHAR(64);
DECLARE table_name VARCHAR(64);
DECLARE id bigint;
DECLARE time bigint;
DECLARE info longtext;
DECLARE curMdlCount INT DEFAULT 0;
DECLARE curMdlCtr INT DEFAULT 0;
DECLARE curMdl CURSOR FOR SELECT * FROM tmp_blocked_metadata;
DROP TEMPORARY TABLE IF EXISTS tmp_blocked_metadata;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_blocked_metadata (
table_schema varchar(64),
table_name varchar(64),
id bigint,
time bigint,
info longtext,
PRIMARY KEY(table_schema, table_name)
);
REPLACE tmp_blocked_metadata(table_schema,table_name,id,time,info) SELECT mdl.OBJECT_SCHEMA, mdl.OBJECT_NAME, t.PROCESSLIST_ID, t.PROCESSLIST_TIME, t.PROCESSLIST_INFO FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON mdl.OWNER_THREAD_ID = t.THREAD_ID WHERE mdl.LOCK_STATUS='PENDING' and mdl.LOCK_TYPE='EXCLUSIVE' ORDER BY mdl.OBJECT_SCHEMA,mdl.OBJECT_NAME,t.PROCESSLIST_TIME ASC;
OPEN curMdl;
SET curMdlCount = (SELECT FOUND_ROWS());
WHILE (curMdlCtr < curMdlCount)
DO
FETCH curMdl INTO table_schema, table_name, id, time, info;
SELECT CONCAT_WS(' ','PID',t.PROCESSLIST_ID,'has metadata lock on', CONCAT(mdl.OBJECT_SCHEMA,'.',mdl.OBJECT_NAME), 'with current state', CONCAT_WS('','[',t.PROCESSLIST_STATE,']'), 'for', t.PROCESSLIST_TIME, 'seconds and is currently running', CONCAT_WS('',"[",t.PROCESSLIST_INFO,"]")) AS 'Process(es) that have the metadata lock' FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON t.THREAD_ID = mdl.OWNER_THREAD_ID WHERE mdl.LOCK_STATUS='GRANTED' AND mdl.OBJECT_SCHEMA = table_schema and mdl.OBJECT_NAME = table_name AND mdl.OWNER_THREAD_ID NOT IN(SELECT mdl2.OWNER_THREAD_ID FROM performance_schema.metadata_locks mdl2 WHERE mdl2.LOCK_STATUS='PENDING' AND mdl.OBJECT_SCHEMA = mdl2.OBJECT_SCHEMA and mdl.OBJECT_NAME = mdl2.OBJECT_NAME);
SELECT CONCAT_WS(' ','PID', id, 'has been waiting for metadata lock on',CONCAT(table_schema,'.', table_name),'for', time, 'seconds to execute', CONCAT_WS('','[',info,']')) AS 'Oldest process waiting for metadata lock';
SET curMdlCtr = curMdlCtr + 1;
SELECT CONCAT_WS(' ','PID', t.PROCESSLIST_ID, 'has been waiting for metadata lock on',CONCAT(table_schema,'.', table_name),'for', t.PROCESSLIST_TIME, 'seconds to execute', CONCAT_WS('','[',t.PROCESSLIST_INFO,']')) AS 'Other queries waiting for metadata lock' FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON t.THREAD_ID = mdl.OWNER_THREAD_ID WHERE mdl.LOCK_STATUS='PENDING' AND mdl.OBJECT_SCHEMA = table_schema and mdl.OBJECT_NAME = table_name AND mdl.OWNER_THREAD_ID AND t.PROCESSLIST_ID <> id ;
END WHILE;
CLOSE curMdl;
END//
delimiter ;
## 위의 프로시저 수행 시 결과 ##
mysql> CALL test.procShowMetadataLockSummary();
+----------------------------------------------------------------------------------------------------------------+
| Process(es) that have the metadata lock |
+----------------------------------------------------------------------------------------------------------------+
| PID 10 has metadata lock on sbtest.sbtest with current state [] since 274 seconds and is currently running [] |
| PID 403 has metadata lock on sbtest.sbtest with current state [] since 291 seconds and is currently running [] |
+----------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
+------------------------------------------------------------------------------------------------------------------------+
| Oldest process waiting for metadata lock |
+------------------------------------------------------------------------------------------------------------------------+
| PID 1264 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [truncate table sbtest.sbtest] |
+------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
+---------------------------------------------------------------------------------------------------------------------------+
| Other queries waiting for metadata lock |
+---------------------------------------------------------------------------------------------------------------------------+
| PID 1269 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [SELECT c from sbtest where id=?] |
| PID 1270 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [SELECT c from sbtest where id=?] |
| PID 1271 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [SELECT c from sbtest where id=?] |
| PID 1272 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [SELECT c from sbtest where id=?] |
| PID 1273 has been waiting for metadata lock on sbtest.sbtest for 264 seconds to execute [SELECT c from sbtest where id=?] |
+---------------------------------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)
- MariaDB 에서 이를 확인 할 수 있는 방법은 아래와 같다. (출처:https://mariadb.com/kb/en/metadata-lock-info-plugin/)
- METADATA_LOCK_INFO 라는 테이블을 사용 할 수 있다. 이를 위해서는 동명의 Plugin을 설치하거나 my.cnf 에 기입 해야 한다. (10.0.7 이상의 버전부터 사용 가능)
- INSTALL SONAME 'metadata_lock_info'; 혹은 파라미터 기입
- METADATA_LOCK_INFO 라는 테이블을 사용 할 수 있다. 이를 위해서는 동명의 Plugin을 설치하거나 my.cnf 에 기입 해야 한다. (10.0.7 이상의 버전부터 사용 가능)
[mariadb]
...
plugin_load_add = metadata_lock_info
-
- metadata_lock_info 테이블 에서 아래와 같이 조회 가
- metadata_lock_info 테이블 에서 아래와 같이 조회 가
SELECT * FROM information_schema.metadata_lock_info;
+-----------+--------------------------+---------------+----------------------+-----------------+-------------+
| THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA | TABLE_NAME |
+-----------+--------------------------+---------------+----------------------+-----------------+-------------+
| 31 | MDL_INTENTION_EXCLUSIVE | MDL_EXPLICIT | Global read lock | | |
| 31 | MDL_INTENTION_EXCLUSIVE | MDL_EXPLICIT | Commit lock | | |
| 31 | MDL_INTENTION_EXCLUSIVE | MDL_EXPLICIT | Schema metadata lock | dbname | |
| 31 | MDL_SHARED_NO_READ_WRITE | MDL_EXPLICIT | Table metadata lock | dbname | exotics |
+-----------+--------------------------+---------------+----------------------+-----------------+-------------+
4 rows in set (0.00 sec)
-
- 응용하면 아래의 예시를 만들 수도 있다.
SELECT
CONCAT('Thread ',P.ID,' executing "',P.INFO,'" IS LOCKED BY Thread ',
M.THREAD_ID) WhoLocksWho
FROM INFORMATION_SCHEMA.PROCESSLIST P,
INFORMATION_SCHEMA.METADATA_LOCK_INFO M
WHERE LOCATE(lcase(LOCK_TYPE), lcase(STATE))>0;
+-----------------------------------------------------------------------------------+
| WhoLocksWho |
+-----------------------------------------------------------------------------------+
| Thread 3 executing "INSERT INTO foo ( b ) VALUES ( 'FOO' )" IS LOCKED BY Thread 2 |
+-----------------------------------------------------------------------------------+
1 row in set (0.00 sec)
SHOW PROCESSLIST;
+----+------+-----------+------+---------+------+------------------------------+----------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+------+-----------+------+---------+------+------------------------------+----------------------------------------+----------+
| 2 | root | localhost | test | Sleep | 123 | | NULL | 0.000 |
| 3 | root | localhost | test | Query | 103 | Waiting for global read lock | INSERT INTO foo ( b ) VALUES ( 'FOO' ) | 0.000 |
| 4 | root | localhost | test | Query | 0 | init | SHOW PROCESSLIST | 0.000 |
+----+------+-----------+------+---------+------+------------------------------+----------------------------------------+----------+
3 rows in set (0.00 sec)
'MySQL > 아키텍처 및 내부 구조' 카테고리의 다른 글
MySQL / MariaDB 기본 아키텍처 (쿼리 실행 과정) (0) | 2021.03.16 |
---|---|
MySQL / MariaDB 기본 아키텍처 (Engine) (0) | 2021.03.12 |
MySQL / MariaDB (InnoDB 기준) index 종류 (0) | 2021.03.10 |
MySQL / MariaDB 트랜잭션 Isolation Level (0) | 2021.03.03 |
MySQL / MariaDB MVCC (0) | 2021.03.03 |