글을 작성하게 된 계기
TRUNCATE 쿼리가 트랜잭션에 영향을 받는지 실험을 하게 됐고, 이를 정리하기 위해 글을 작성하게 되었습니다.
1. TRUNCATE
TRUNCATE은 MySQL에서 테이블의 모든 데이터를 빠르게 제거하는 DDL(Data Definition Language) 문으로, DELETE와는 다르게 동작합니다.
주요 특징은 다음과 같습니다. 이 중 살펴볼 부분은 암묵적 커밋 발생, 격리 수준과 무관하게 즉시 반영 인데요, 간단한 실험을 트랜잭션과 TRUNCATE 명령어의 관계를 살펴보겠습니다.
암묵적 커밋 발생: TRUNCATE는 DDL로 분류되어 자동으로 커밋 됩니다. 따라서 트랜잭션 내에서 실행하더라도 롤백이 불가능합니다.격리 수준과 무관하게 즉시 반영: 어떤 ISOLATION LEVEL을 사용해도, TRUNCATE는 즉시 커밋되며 다른 트랜잭션에서도 바로 반영됩니다.ON DELETE 트리거 미동작: DELETE와 달리 ON DELETE 트리거를 발생시키지 않으며, 내부적으로는 DROP + CREATE TABLE에 가까운 처리 방식입니다.외래키 제약조건 있는 경우 실패: 외부 테이블로부터 외래키로 참조되고 있다면 InnoDB 테이블은 TRUNCATE 불가합니다.AUTO_INCREMENT 초기화: 테이블의 AUTO_INCREMENT 값이 초기값으로 리셋됩니다.성능: 내부적으로 데이터를 한 건씩 지우는 것이 아니라 테이블 자체를 재생성하므로 대량 데이터 처리 시 DELETE보다 훨씬 빠릅니다.
2. 실험
간단한 테이블을 만들어서 TRUNCATE 쿼리가 트랜잭션에 영향을 받는지 살펴보겠습니다. 먼저 테이블 생성 후, 데이터를 삽입해줍니다.
1
2
3
4
5
CREATE TABLE users (
user_id INT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
username VARCHAR(100) NOT NULL
);
1
2
3
INSERT INTO users (user_id, email, username)
VALUES (1, 'a@test.com', 'a'),
(2, 'b@test.com', 'b');
다음으로 트랜잭션을 열고, 데이터가 들어가 있는지 조회해보겠습니다.
1
2
3
4
5
6
7
8
9
START TRANSACTION;
SELECT * FROM users;
+---------+------------+----------+
| user_id | email | username |
+---------+------------+----------+
| 1 | a@test.com | a |
| 2 | b@test.com | b |
+---------+------------+----------+
이제 TRUNCATE 쿼리를 실행해보겠습니다.
1
TRUNCATE TABLE users;
이후, 새로운 shell 창을 열어서 다른 트랜잭션 에서 데이터가 삭제되었는지 조회해보겠습니다. 아직 왼쪽 창에서 커밋을 하지 않았는데도 데이터가 없는 것을 볼 수 있는데요, 즉, 암묵적 커밋 발생, 격리 수준과 무관하게 즉시 반영 된 것을 알 수 있습니다.
3. TRUNCATE 쿼리를 한 번에 실행할 수 있을까?
회사의 데이터베이스에는 수 백 개의 테이블이 존재합니다. TRUNCATE 쿼리를 한 번 실행하면 수 백 번의 커넥션이 맺어지는데, 이를 한 번에 모아서 실행 하면 데이터베이스와 통신하는 횟수가 줄어들지 않을까요?
현재 자주 사용하는 한 데이터베이스의 테이블만 650개 정도입니다.
결론부터 말하면 TRUNCATE 쿼리를 한 번에 실행할 수 없습니다. MySQL의 경우 TRUNCATE 쿼리는 암묵적인 커밋 을 하기 때문에, 한 번 실행한 TRUNCATE 쿼리는 자동으로 커밋 되며, 더 이상 추가적인 작업이 불가능하기 때문입니다. 이에 대한 자세한 글은 해당 링크를 참고하시기 바랍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
class DatabaseCleaner {
......
void executeQuery() {
final String[] tables = {"table1", "table2", "table3"};
final StringBuilder queryBuilder = new StringBuilder();
for (final String table : tables) {
queryBuilder.append("TRUNCATE TABLE ").append(table).append("; ");
}
jdbcTemplate.execute(queryBuilder.toString());
}
}
4. 정리
TRUNCATE 명령어가 어떤 특징을 가지는지 살펴보았습니다. 평소에 이를 잘 사용하고 있었는데, 트랜잭션에 영향을 받지 않는다는 점과 하나씩 실행되는지는 모르고 있었네요. 회사 레거시를 청산하며 이런 내용도 알게 되고, 참 재밌네요.