MySQL에서 Lock(락)은 여러 트랜잭션이 동일한 데이터에 접근할 때 발생할 수 있는 데이터 불일치, 데드락, 성능 저하 등의 문제를 방지하는 중요한 개념이다.
데이터베이스는 다수의 사용자가 동시에 데이터를 읽고 쓸 수 있어야 하지만, 여러 트랜잭션이 동일한 데이터를 수정하거나 삭제하려고 하면 경쟁 상태(Race Condition) 가 발생할 수 있다. 이를 방지하기 위해 Lock을 사용하여 트랜잭션이 특정 데이터에 대한 작업을 완료할 때까지 다른 트랜잭션의 접근을 제한할 수 있다.
MySQL의 락은 크게 MySQL 엔진 수준의 락과 스토리지 엔진 수준의 락으로 나뉜다. 이번 글에서는 MySQL 엔진 수준의 락을 중점적으로 살펴보고, 데이터의 일관성(Consistency)과 무결성(Integrity) 을 유지하는 방법에 대해 알아본다.
MySQL 엔진 수준의 락
MySQL 엔진 자체에서 관리하는 락으로, 주로 테이블 또는 세션 단위에서 작동한다.
🔑 전역 락 (Global Lock)
전역 락 (Global Lock)은 MySQL 서버 전체를 읽기 전용 모드로 변경하는 락이다. 특정 작업 중에 전체 데이터베이스의 정합성을 유지해야 할 경우 유용하게 사용된다.
전역 락이 필요한 경우
- 데이터 백업(Backup) 시 일관된 상태 유지
- 대량의 데이터를 이관(Migration) 하는 경우
- 비즈니스 운영 중 특정 시간대에 데이터 변경을 제한하는 경우
예제
FLUSH TABLES WITH READ LOCK;
- 모든 테이블을 읽기 전용 상태로 설정하여 백업을 안전하게 수행할 수 있다.
UNLOCK TABLES;
- 백업이 완료된 후 전역 락을 해제하여 정상적으로 작업을 진행할 수 있다.
⚠️ 주의!!: 전역 락이 설정되면 모든 쓰기 작업 (INSERT, UPDATE, DELETE)이 차단되므로, 장시간 사용하면 서비스 운영에 영향을 미칠 수 있다.
🔑 테이블 락 (Table Lock)
테이블 락(Table Lock)은 특정 테이블 단위로 설정되는 락으로, MyISAM과 MEMORY 스토리지 엔진에서 주로 사용된다. InnoDB에서는 기본적으로 행 단위 락(Row Lock)을 사용하지만, 명시적으로 테이블 락을 걸 수도 있다.
테이블 락이 필요한 경우
- 대량의 데이터를 일괄 삽입(Bulk Insert)하는 경우
- MyISAM 엔진을 사용할 경우, 동시성이 낮아도 빠른 성능을 원하는 경우
- 테이블 구조 변경(ALTER TABLE) 작업을 안전하게 수행하길 원하는 경우
이러한 테이블 락은 읽기 락(READ LOCK)과 쓰기 락(WRITE LOCK)으로 구분된다.
읽기 락 (READ LOCK)
LOCK TABLES employees READ;
- 여러 트랜잭션이 해당 테이블을 읽을 수 있지만, 쓰기(INSERT, UPDATE, DELETE)는 불가능하다.
쓰기 락 (WRITE LOCK)
LOCK TABLES employees WRITE;
- 해당 테이블을 단독 점유하여 읽기 및 쓰기 모두 불가능하게 설정된다.
예제: 테이블 락을 이용한 안전한 데이터 마이그레이션
LOCK TABLES employees WRITE;
INSERT INTO employees_archive SELECT * FROM employees;
DELETE FROM employees;
UNLOCK TABLES;
- 데이터 마이그레이션 과정에서 원본 테이블을 보호하고 데이터 정합성을 유지하기 위해 테이블 락을 설정하는 방식
📌 테이블 락(Table Lock)을 사용하는 이유
일반적으로 Row-level Lock(행 락)이 비교적 세밀한 제어를 제공하므로 동시성을 높이는 데 유리하지만, Table-level Lock(테이블 락)이 필요한 경우도 있다.
1. 트랜잭션이 아닌 DDL(스키마 변경) 작업을 보호하기 위해
MySQL에서 테이블 구조를 변경(ALTER TABLE, DROP TABLE 등)하는 작업은 Row-level Lock이 아니라 Table-level Lock을 필요로 한다. 이는 스키마 변경 작업(DDL)은 전체 테이블의 데이터를 변경할 가능성이 크기 때문이다.
예제: 테이블 구조 변경(DDL)
-- Transaction A: 특정 행에 대한 Shared Lock 설정
START TRANSACTION;
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;
-- Transaction B: 테이블 구조 변경 (대기 상태)
ALTER TABLE users ADD COLUMN email VARCHAR(255); -- 🚫 블로킹됨!
- LOCK IN SHARE MODE는 특정 행(Row)만 잠그지만, ALTER TABLE은 테이블 전체에 대한 락을 필요로 함.
- 따라서, ALTER TABLE은 Row-level Lock과 공존할 수 없고, 테이블 락이 필요하다.
2. 대량의 데이터를 일괄적으로 수정하거나 삭제할 때
일반적으로 MySQL의 InnoDB 스토리지 엔진은 Row-level Lock을 사용하지만, 대량의 데이터(예: 수백만 개의 행)를 업데이트 또는 삭제하는 경우 Row-level Lock보다 Table-level Lock이 더 효율적일 수 있다.
예제: 대량 데이터 수정
LOCK TABLE users WRITE;
UPDATE users SET status = 'inactive' WHERE last_login < '2023-01-01';
UNLOCK TABLES;
- 수백만 개의 데이터를 한 번에 수정하는 경우, 개별 Row Lock을 설정하는 것보다 Table Lock을 사용하여 트랜잭션을 빠르게 수행하는 것이 효율적이다.
- 개별 행에 락을 설정하면 락 오버헤드(lock overhead)가 증가하여 성능이 저하될 수 있다.
3. MyISAM 스토리지 엔진을 사용할 때 (MySQL 5.7 이하)
- MySQL의 MyISAM 엔진은 Row-level Lock을 지원하지 않고, 테이블 락만 지원한다.
- 따라서, MyISAM에서는 개별 행을 수정하거나 조회할 때도 테이블 락을 사용해야 한다.
예제: MyISAM에서는 테이블 단위 락 사용
LOCK TABLE users READ;
SELECT * FROM users WHERE id = 1;
UNLOCK TABLES;
- InnoDB에서는 Row-level Lock을 사용할 수 있지만, MyISAM에서는 테이블 단위로 락을 걸어야 한다.
4. 백업, 데이터 마이그레이션 등 일괄 작업 수행 시
백업을 실행하거나, 특정 테이블을 다른 데이터베이스로 마이그레이션하는 경우, 데이터 정합성을 보장하기 위해 테이블 락을 사용할 수 있다.
예제: 백업 중 테이블 변경 방지
LOCK TABLE users READ; -- 다른 트랜잭션이 데이터를 변경하지 못하도록 READ LOCK 설정
SELECT * FROM users INTO OUTFILE '/backup/users_backup.sql';
UNLOCK TABLES;
- LOCK TABLE users READ를 사용하면, 다른 트랜잭션이 데이터를 수정하지 못하도록 막음.
- 데이터를 백업하는 동안 변경이 발생하면 백업 파일과 실제 데이터가 불일치할 수 있으므로, 테이블 락이 필요하다.
5. 트랜잭션을 지원하지 않는 작업을 동기화하기 위해
MySQL의 일부 작업은 트랜잭션을 지원하지 않기 때문에, 테이블 락을 사용하여 동기화해야 한다.
예제: AUTO_INCREMENT 값을 동기화
LOCK TABLE invoices WRITE;
INSERT INTO invoices (customer_id, amount) VALUES (1, 1000);
UNLOCK TABLES;
- AUTO_INCREMENT 컬럼을 사용하는 경우, 여러 트랜잭션이 동시에 실행되면 번호 충돌이 발생할 가능성이 있음.
- 이를 방지하기 위해 LOCK TABLE ... WRITE를 사용하여 순차적으로 실행되도록 보장할 수 있다.
2️⃣ 테이블 락과 행 락 비교
구분 Row Lock (행 락) Table Lock (테이블 락)
적용 범위 특정 행(Row) 테이블 전체
동시성 높음 (다른 행 접근 가능) 낮음 (테이블 전체가 락됨)
사용 목적 특정 행만 수정/조회 시 대량 데이터 수정/삭제, 스키마 변경, 백업 등
DDL 영향 없음 (테이블 변경 가능) 테이블 변경 불가능
트랜잭션 지원 지원됨 (InnoDB) 일부 작업에 필요
스토리지 엔진 InnoDB InnoDB, MyISAM
구분 | Row Lock (행 락) | Table Lock (테이블 락) |
적용 범위 | 특정 행 (Row) | 테이블 전체 |
동시성 | 높음 (다른 행 접근 가능) | 낮음 (테이블 전체가 락됨) |
사용 목적 | 특정 행만 수정/조회 시 | 대량 데이터 수정/삭제, 스키마 변경, 백업 등 |
DDL 영향 | 없음 (테이블 변경 가능) | 테이블 변경 불가능 |
트랜잭션 지원 | 지원됨 (InnoDB) | 일부 작업에 필요 |
스토리지 엔진 | InnoDB | InnoDB, MyISAM |
'기술(Tech) > Database' 카테고리의 다른 글
Prefix Index를 기본적으로 사용하지 않는 이유 (0) | 2025.01.12 |
---|---|
Index Dive (0) | 2025.01.06 |
INSERT 쿼리 최적화 (0) | 2025.01.05 |
MySQL filesort (0) | 2024.12.30 |
ORDER BY와 인덱스의 관계 + sort_buffer_size (0) | 2024.12.27 |