Transcation 과 Lock
1. Transcation
- 논리적인 작업단위로 전부터리되거나 처리되지 않는 (Commit / Rollback) 원자성을 보장하기 위한 기능이다.
- MySQL InnoDB의 격리 레벨(isolation level)이 REPEATABLE TABLE 이다.
show session variables like '%isola%'; +-----------------------+-----------------+ | Variable_name | Value | +-----------------------+-----------------+ | transaction_isolation | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.01 sec) |
격리 수준 | DIRTY READ | NON-REPEATABLE READ | PHANTOM READ |
READ UNCOMMITTED | O | O | O |
READ COMMITTED | O | O | |
REPEATABLE READ | O(InnoDB는 발생 X) | ||
SERIALIZABLE |
참고 : https://zzang9ha.tistory.com/381
2. Lock
- 서로 다른 작업에 같은 자원을 동시에 필요로 할 때 자원 경쟁이 일어나는데, 이때 순서대로 사용되는 동시성을 보장하기 위한 기능이다.
-. MySQL에서 사용되는 Lock은 크게 MySQL 엔진 레벨의 Lock과 스토리지 엔진 레벨의 Lock이 있다.
InnoDB 스토리지 레벨의 락
-. 기본적으로 비관적 락(Perssimistic locking)을 사용한다.
- 비관적 락
Trascation에서 변경하려는 레코드에 대해 락을 획득하고 쿼리를 수행하는 방식 - 낙관적 락
Transcation에서 Lock 없이 일단 쿼리 수행을 하고 마칠 때 서로 다른 트랜잭션에서 충돌이 있었는지 확인하고 문제가 있으면 충돌이 난 트랜잭션을 롤백하는 방식.
# 보통 대규모 트래픽을 처리하는 애플리케이션에서는 성능 이슈 떄문에 Lock을 최소화 해야하기 때문에 낙관적 락으로 변경하여 사용하기도 한다.
1. 락이 적용되는 상황에 따른 분류
1.1 로우 락 (Row Lock)
|
2. 락 적용 요소에 따른 분류
2.1 Shared Lock (공유 잠금)
2.2 Exclusive Lock(베타적 잠금)
|
Share Lock, Exclusive Lock, Intention Lock 호환 표
X | IX | S | IS | |
X | 충돌 | 충돌 | 충돌 | 충돌 |
IX | 충돌 | 호환 | 충돌 | 호환 |
S | 충돌 | 충돌 | 호환 | 호환 |
IS | 충돌 | 호환 | 호환 | 호환 |
MySQL 엔진 레벨의 락
- 글로벌 락
- 모든 테이블에 잠금을 건다.
- "FLUSH TABLES WITH READ LOCK" 명령으로 락을 걸 수 있는데 굳이 일부러 걸지 않는다. 특히나 운영 중에 전체를 멈추는 락을 건다는 건 서비스 장애로 이어지기 때문이다.
- 테이블 락
- 각각 테이블에 테이블 단위로 락을 건다.
- MySQL InnoDB는 기본적으로 스토리지에서 레코드 락을 사용하므로 DML에서는 주로 사용되지 않지만, DDL 같이 테이블의 스키마에 변화를 줄 때는 사용된다.
- 마찬가지로 특정 명령어로 락을 걸 수 있으나 이 역시도 장애로 이어질 확률이 높아서 명시적으로 사용하지는 않는다.
- 네임 락
- 테이블 또는 뷰등의 스키마 객체의 이름을 변경하는 경우(rename ...)에 자동으로 락을 건다.
- 유저 락
- 사용자가 지정한 문자열에 락을 건다.
MySQL 5.7
-. 5.7 버전에서는 실제 lock wait가 발생해야 Lock관련 정보가 조회된다.
Lock 경합이 없는 상황에서는 실행중인 Transcation이 어떤 Lock를 잡고있는지 조회 불가
1. MySQL 5.7 Lock 조회 쿼리
SELECT straight_join
w.trx_mysql_thread_id waiting_thread,
w.trx_id waiting_trx_id,
w.trx_query waiting_query,
b.trx_mysql_thread_id blocking_thread,
b.trx_id blocking_trx_id,
b.trx_query blocking_query,
bl.lock_id blocking_lock_id,
bl.lock_mode blocking_lock_mode,
bl.lock_type blocking_lock_type,
bl.lock_table blocking_lock_table,
bl.lock_index blocking_lock_index,
wl.lock_id waiting_lock_id,
wl.lock_mode waiting_lock_mode,
wl.lock_type waiting_lock_type,
wl.lock_table waiting_lock_table,
wl.lock_index waiting_lock_index
FROM
information_schema.INNODB_LOCK_WAITS ILW ,
information_schema.INNODB_TRX b ,
information_schema.INNODB_TRX w ,
information_schema.INNODB_LOCKS bl ,
information_schema.INNODB_LOCKS wl
WHERE
b.trx_id = ilw.blocking_trx_id
AND w.trx_id = ilw.requesting_trx_id
AND bl.lock_id = ilw.blocking_lock_id
AND wl.lock_id = ilw.requested_lock_id;
MySQL 8.0
1. MySQL 8.0 Lock 조회 쿼리
1. 현재 접속 세션 확인
select * FROM information_schema.PROCESSLIST p
order by STATE ;
2. LOCK 조회에서 해당 thread 죽이기
-- MySQL row level
SELECT straight_join
dl.ENGINE_TRANSACTION_ID,
dl.THREAD_ID
, est.SQL_TEXT
, dl.OBJECT_SCHEMA
, dl.OBJECT_NAME
, dl.INDEX_NAME
, dl.LOCK_TYPE
, dl.LOCK_MODE
, dl.LOCK_STATUS
, dl.LOCK_DATA
FROM
performance_schema.data_locks dl inner join performance_schema.events_statements_current est
on dl.THREAD_ID = est.THREAD_ID
ORDER BY est.TIMER_START,dl.OBJECT_INSTANCE_BEGIN;
-- Mysql InnoDB level
select
*
FROM information_schema.INNODB_TRX
where trx_id = 'Thread level에서 조회 된 ENGINE_TRANSACTION_ID';
-- Mysql Process level
select * FROM information_schema.PROCESSLIST p
where id = 'InnoDB level에서 조회된 trx_mysql_thread_id' ;
-- lock 잡고있는 process 죽이기
kill 'trx_mysql_mysql_thread_id';
4. hierarchy lock
select *
FROM information_schema.INNODB_TRX a,
( SELECT straight_join
dl.ENGINE_TRANSACTION_ID trx_id,
dl.THREAD_ID
, est.SQL_TEXT
, dl.OBJECT_SCHEMA
, dl.OBJECT_NAME
, dl.INDEX_NAME
, dl.LOCK_TYPE
, dl.LOCK_MODE
, dl.LOCK_STATUS
, dl.LOCK_DATA
FROM
performance_schema.data_locks dl inner join performance_schema.events_statements_current est
on dl.THREAD_ID = est.THREAD_ID
ORDER BY est.TIMER_START,dl.OBJECT_INSTANCE_BEGIN) b
where a.trx_id = b.trx_id
order by a.trx_id, a.trx_state ;
5. plan
explain
select * from test_tab1;
6. top 5 sql
SELECT * FROM mysql.slow_log
order by query_time desc
limit 5;
3. LOCK mode 별 count
select LOCK_MODE,COUNT(*)
from performance_schema.data_locks
group by LOCK_MODE;
# Row Level Lock
SELECT T.PROCESSLIST_ID, T.PROCESSLIST_HOST, T.PROCESSLIST_USER
, CONCAT(A.OBJECT_SCHEMA,'.',A.OBJECT_NAME) LOCKED_OBJ
, (SELECT SEC_TO_TIME (SYSDATE() - TRX_STARTED)
FROM INFORMATION_SCHEMA.INNODB_TRX
WHERE TRX_MYSQL_THREAD_ID=T.PROCESSLIST_ID ) LOCK_TIME
, LOCK_TYPE
, LOCK_MODE
, IFNULL(T.PROCESSLIST_INFO
,(SELECT SQL_TEXT FROM PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_CURRENT WHERE THREAD_ID = T.THREAD_ID)
) SQLTEXT
FROM PERFORMANCE_SCHEMA.DATA_LOCKS A
, PERFORMANCE_SCHEMA.THREADS T
WHERE A.THREAD_ID=T.THREAD_ID
;
# Lock(Blocking, Waiting)
SELECT
(SELECT PROCESSLIST_USER FROM PERFORMANCE_SCHEMA.THREADS WHERE THREAD_ID=A.BLOCKING_THREAD_ID) BLOCKING_USER
, (SELECT PROCESSLIST_USER FROM PERFORMANCE_SCHEMA.THREADS WHERE THREAD_ID=A.REQUESTING_THREAD_ID) WAITING_USER
, (SELECT PROCESSLIST_ID FROM PERFORMANCE_SCHEMA.THREADS WHERE THREAD_ID=A.BLOCKING_THREAD_ID) BLOCKING_THR
, (SELECT PROCESSLIST_ID FROM PERFORMANCE_SCHEMA.THREADS WHERE THREAD_ID=A.REQUESTING_THREAD_ID) WAITING_THR
, (SELECT CONCAT(OBJECT_SCHEMA,'.',OBJECT_NAME) FROM PERFORMANCE_SCHEMA.DATA_LOCKS WHERE ENGINE_LOCK_ID=A.REQUESTING_ENGINE_LOCK_ID) LOCKED_OBJ
, (SELECT LOCK_TYPE FROM PERFORMANCE_SCHEMA.DATA_LOCKS WHERE ENGINE_LOCK_ID = A.REQUESTING_ENGINE_LOCK_ID) REQUEST_MODE
, (SELECT LOCK_MODE FROM PERFORMANCE_SCHEMA.DATA_LOCKS WHERE ENGINE_LOCK_ID = A.BLOCKING_ENGINE_LOCK_ID) HOLDING_MODE
, (SELECT PROCESSLIST_INFO FROM PERFORMANCE_SCHEMA.THREADS WHERE THREAD_ID = A.REQUESTING_THREAD_ID) SQL_TEXT
FROM PERFORMANCE_SCHEMA.DATA_LOCK_WAITS A
;
2. Mysql 서버에서 지정 시간 간격으로 Processlist 자동 조회
mysqladmin -u root -p processlist -i 5 |
3. 현재 Auto commit 값 확인
select @@AUTOCOMMIT; |
4. Auto commit 해제
SET AUTOCOMMIT = 1; -- 1이면 auto commin이 켜져있는 것이다. SET AUTOCOMMIT = 0; |
MySQL SQL 처리 과정
1. Query Cache
먼저 Query를 분석하기 전에 MySQL Server는 Cache를 확인합니다. Query Cache는 Select문에 대한 전체 결과 집합을 저장하고 있습니다. Client가 Query 수행 시 제일 먼저 거치는 단계로, Query를 분석하기 전에 MySQL Server는 Query Cache를 참고합니다. Client가 이미 캐시에 있는 것과 동일한 Query를 실행하면 Server는 SQL Parser, Optimizer 단계를 건너 뛰고 결과를 직접 반환합니다.
테이블의 Data가 변경되면 Query Cache의 내용 역시 달라지므로 변경된 테이블과 관련된 정보를 모두 삭제해야 했습니다. 이는 심각가한 동시 처리 기능 저하를 유발하고 많은 버그의 원인이 되었기에 MySQL 8.0으로 올라오면서 Query Cache는 MySQL SEerver의 기능에서 완전히 제거 되었습니니다. |
ISAM 엔진 vs INNODB LOCK 구조
Details | MyISAM | InnoDB |
Transaction | - 테이블 락을 기본으로 insert, update, delete가 이루어진다. | - ib_logfileN log 파일을 통하여 대량의 트랜잭션을 버퍼링하고 serialization - 로그파일은 최소 2개의 그룹이며, 서로 rotate 스위칭되며 갱신되어 데이터를 파일로 적용한다. - Transation 이외에 Foreign Key, Trigger를 지원 |
Lock | - Table 단위 Lock 사용 - COUNT(*) 정보를 별도 저장 |
- 행(Row)단위 Lock을 사용 |
#참고
https://jeong-pro.tistory.com/241 https://blog.ex-em.com/1683 https://kdhyo98.tistory.com/101 |
'Database > MYSQL' 카테고리의 다른 글
[MYSQL] 실행된 SQL 쿼리 확인 (0) | 2022.10.30 |
---|---|
[MYSQL] Cluster Index (0) | 2022.10.30 |
[MYSQL] PMM 모니터링 (0) | 2022.10.21 |
[MYSQL] MYSQL 아키텍처 (0) | 2022.10.21 |
[MYSQL] 모니터링 쿼리 (0) | 2022.10.19 |