icon

안동민 개발노트

3장 : SQL 기초 — DDL

테이블 수정과 삭제


한 번 만든 테이블이 영원히 그대로 유지되는 일은 없습니다. 서비스가 성장하면 새로운 기능을 위해 컬럼을 추가해야 하고, 요구사항이 바뀌면 데이터 타입을 변경해야 하며, 불필요한 테이블은 정리해야 합니다. 이런 테이블 구조 변경을 담당하는 DDL 명령이 ALTER TABLE, DROP TABLE, TRUNCATE TABLE입니다.

하지만 운영 중인 데이터베이스의 스키마를 변경하는 것은 매우 위험한 작업입니다. 수백만 행이 들어 있는 테이블에 NOT NULL 컬럼을 추가하면 테이블 전체에 락이 걸려 서비스가 멈출 수 있고, 컬럼 타입을 변경하면 기존 데이터가 변환에 실패할 수 있습니다. 그래서 스키마 변경은 문법을 아는 것만큼이나 어떻게 안전하게 변경할 것인가를 아는 것이 중요합니다.

이 절에서는 ALTER TABLE의 다양한 사용법, DROP TABLE과 TRUNCATE TABLE의 차이, 운영 중 스키마 변경의 위험과 안전한 마이그레이션 전략, 그리고 DBMS별 온라인 DDL 지원 현황까지 다룹니다.


ALTER TABLE — 테이블 구조 변경

ALTER TABLE은 이미 생성된 테이블의 구조를 변경하는 DDL 명령입니다. 컬럼 추가, 수정, 삭제, 이름 변경, 제약 조건 관리 등 다양한 작업을 수행할 수 있습니다. DDL이므로 실행 즉시 자동 커밋되며, ROLLBACK으로 되돌릴 수 없습니다.

컬럼 추가 (ADD)

컬럼 추가
-- Oracle: 괄호 필요
ALTER TABLE employees ADD (phone VARCHAR2(20));
ALTER TABLE employees ADD (
    phone VARCHAR2(20),
    address VARCHAR2(200) DEFAULT '미입력'
);

-- MySQL/PostgreSQL: 괄호 불필요
ALTER TABLE employees ADD phone VARCHAR(20);
ALTER TABLE employees ADD COLUMN phone VARCHAR(20);

-- SQL Server
ALTER TABLE employees ADD phone NVARCHAR(20);

데이터가 있는 테이블에 컬럼을 추가하면, 기존 행의 새 컬럼 값은 NULL(또는 DEFAULT 값)이 됩니다. NOT NULL 컬럼을 추가하려면 반드시 DEFAULT 값을 함께 지정해야 합니다. 그렇지 않으면 기존 행이 NOT NULL 제약을 위반하게 되어 에러가 발생합니다.

NOT NULL 컬럼 추가
-- 잘못된 방법 (기존 데이터 때문에 에러)
ALTER TABLE employees ADD grade VARCHAR(10) NOT NULL;
-- ERROR: 기존 행의 grade가 NULL이므로 제약 위반

-- 올바른 방법 1: DEFAULT 값 함께 지정
ALTER TABLE employees ADD grade VARCHAR(10) NOT NULL DEFAULT 'JUNIOR';

-- 올바른 방법 2: 단계적 추가
ALTER TABLE employees ADD grade VARCHAR(10);            -- NULL 허용으로 추가
UPDATE employees SET grade = 'JUNIOR' WHERE grade IS NULL; -- 값 채우기
ALTER TABLE employees MODIFY grade VARCHAR(10) NOT NULL;   -- NOT NULL 적용

단계적 추가 방법이 운영 환경에서는 더 안전합니다. DEFAULT 값이 모든 행에 적절하지 않을 수 있기 때문입니다.

컬럼에 추가할 위치 지정 (MySQL 전용)

MySQL에서는 컬럼을 추가할 위치를 지정할 수 있습니다. Oracle, PostgreSQL, SQL Server에서는 이 기능을 지원하지 않습니다(항상 마지막에 추가됨).

MySQL 위치 지정
-- 첫 번째 컬럼으로 추가
ALTER TABLE employees ADD employee_code VARCHAR(20) FIRST;

-- 특정 컬럼 뒤에 추가
ALTER TABLE employees ADD phone VARCHAR(20) AFTER email;

컬럼 수정 (MODIFY / ALTER COLUMN)

기존 컬럼의 데이터 타입, 크기, DEFAULT 값, NULL 허용 여부를 변경합니다.

컬럼 수정
-- Oracle: MODIFY
ALTER TABLE employees MODIFY (name VARCHAR2(200));
ALTER TABLE employees MODIFY (salary NUMBER(12,2) DEFAULT 0);

-- MySQL: MODIFY
ALTER TABLE employees MODIFY name VARCHAR(200);
ALTER TABLE employees MODIFY name VARCHAR(200) NOT NULL;

-- PostgreSQL: ALTER COLUMN
ALTER TABLE employees ALTER COLUMN name TYPE VARCHAR(200);
ALTER TABLE employees ALTER COLUMN salary SET DEFAULT 0;
ALTER TABLE employees ALTER COLUMN name SET NOT NULL;

-- SQL Server: ALTER COLUMN
ALTER TABLE employees ALTER COLUMN name NVARCHAR(200);

컬럼 수정 시 주의사항이 있습니다. 크기를 줄이면(VARCHAR(200) → VARCHAR(50)) 기존 데이터가 50자를 초과하는 행이 있다면 에러가 발생합니다. 타입을 변경하면(VARCHAR → INT) 기존 데이터가 숫자가 아닌 문자열을 포함하고 있으면 변환에 실패합니다.

컬럼 수정 전 확인
-- 크기 축소 전: 최대 길이 확인
SELECT MAX(LENGTH(name)) FROM employees;  -- 결과: 85
-- 85자 이하로는 줄일 수 없음

-- 타입 변경 전: 변환 가능 여부 확인
SELECT age FROM employees WHERE age NOT REGEXP '^[0-9]+$';
-- 숫자가 아닌 값이 있는지 확인

컬럼 삭제 (DROP COLUMN)

컬럼 삭제
-- 모든 DBMS 공통
ALTER TABLE employees DROP COLUMN phone;

-- Oracle: 여러 컬럼 동시 삭제
ALTER TABLE employees DROP (phone, fax, pager);

-- Oracle: 큰 테이블에서 컬럼 비활성화 (빠름)
ALTER TABLE employees SET UNUSED COLUMN phone;
-- 나중에 실제 삭제
ALTER TABLE employees DROP UNUSED COLUMNS;

Oracle의 SET UNUSED는 대용량 테이블에서 유용합니다. DROP COLUMN은 모든 행에서 해당 컬럼의 데이터를 물리적으로 제거하므로 시간이 오래 걸리지만, SET UNUSED는 데이터 딕셔너리에서 컬럼을 논리적으로 숨기기만 하므로 즉시 완료됩니다. 물리적 제거는 나중에 여유 있을 때 수행할 수 있습니다.

컬럼을 삭제하면 해당 컬럼의 데이터는 영구적으로 사라집니다. 또한 그 컬럼을 참조하는 인덱스, 뷰, 트리거, 프로시저 등도 영향을 받습니다.

컬럼 이름 변경 (RENAME COLUMN)

컬럼 이름 변경
-- Oracle / PostgreSQL
ALTER TABLE employees RENAME COLUMN name TO full_name;

-- MySQL: CHANGE (타입도 함께 명시해야 함)
ALTER TABLE employees CHANGE name full_name VARCHAR(200);

-- MySQL 8.0+: RENAME COLUMN
ALTER TABLE employees RENAME COLUMN name TO full_name;

-- SQL Server: sp_rename 프로시저
EXEC sp_rename 'employees.name', 'full_name', 'COLUMN';

MySQL의 CHANGE는 컬럼 이름과 타입을 동시에 변경할 수 있지만, 이름만 바꾸고 싶어도 타입을 반드시 명시해야 합니다. 실수로 타입을 다르게 적으면 의도치 않은 타입 변경이 발생할 수 있으므로 주의해야 합니다.

테이블 이름 변경

테이블 이름 변경
-- Oracle / MySQL / PostgreSQL
ALTER TABLE employees RENAME TO staff;
-- 또는
RENAME employees TO staff;

-- SQL Server
EXEC sp_rename 'employees', 'staff';

제약 조건 추가/삭제

제약 조건 관리
-- PRIMARY KEY 추가
ALTER TABLE employees ADD CONSTRAINT pk_emp PRIMARY KEY (emp_id);

-- FOREIGN KEY 추가
ALTER TABLE orders ADD CONSTRAINT fk_orders_user
    FOREIGN KEY (user_id) REFERENCES users(user_id);

-- CHECK 제약 추가
ALTER TABLE employees ADD CONSTRAINT ck_age CHECK (age >= 0 AND age <= 150);

-- UNIQUE 제약 추가
ALTER TABLE users ADD CONSTRAINT uq_email UNIQUE (email);

-- NOT NULL 추가 (Oracle)
ALTER TABLE employees MODIFY (name NOT NULL);

-- NOT NULL 추가 (PostgreSQL)
ALTER TABLE employees ALTER COLUMN name SET NOT NULL;
제약 조건 삭제
-- 이름으로 삭제 (모든 DBMS)
ALTER TABLE employees DROP CONSTRAINT ck_age;

-- PRIMARY KEY 삭제
ALTER TABLE employees DROP PRIMARY KEY;

-- MySQL: 인덱스 이름으로 삭제
ALTER TABLE employees DROP INDEX uq_email;

-- NOT NULL 해제 (Oracle)
ALTER TABLE employees MODIFY (name NULL);

-- NOT NULL 해제 (PostgreSQL)
ALTER TABLE employees ALTER COLUMN name DROP NOT NULL;

제약 조건 비활성화/활성화 (Oracle)

운영 중 대량 데이터 적재 시 제약 조건 검사가 성능을 저하시키므로, 일시적으로 비활성화할 수 있습니다.

제약 조건 비활성화/활성화
-- 비활성화
ALTER TABLE employees DISABLE CONSTRAINT ck_age;

-- 활성화 (기존 데이터 검증 포함)
ALTER TABLE employees ENABLE CONSTRAINT ck_age;

-- 활성화 (기존 데이터 검증 건너뛰기 — 새 데이터만 검사)
ALTER TABLE employees ENABLE NOVALIDATE CONSTRAINT ck_age;

ENABLE NOVALIDATE는 기존 데이터가 제약 조건을 위반할 수 있지만, 새로 입력되는 데이터에 대해서만 제약을 적용합니다. 대량 마이그레이션 후 점진적으로 기존 데이터를 정리할 때 유용합니다.


DROP TABLE — 테이블 삭제

DROP TABLE은 테이블 자체를 완전히 제거합니다. 테이블 구조(스키마), 데이터, 인덱스, 트리거, 권한 등 테이블에 속한 모든 것이 삭제됩니다.

DROP TABLE 기본
-- 기본 삭제
DROP TABLE employees;

-- 테이블이 존재할 때만 삭제 (에러 방지)
DROP TABLE IF EXISTS employees;  -- MySQL, PostgreSQL, SQL Server 2016+

-- Oracle에서는 IF EXISTS를 지원하지 않으므로
-- PL/SQL 블록으로 처리
BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE employees';
EXCEPTION
    WHEN OTHERS THEN NULL;
END;

외래키 참조가 있는 테이블 삭제

다른 테이블에서 외래키로 참조하고 있는 테이블은 그냥 삭제할 수 없습니다.

외래키 참조 시 삭제
-- 에러 발생
DROP TABLE users;
-- ERROR: Cannot drop table 'users' referenced by a foreign key constraint

-- Oracle: CASCADE CONSTRAINTS로 참조하는 FK도 함께 삭제
DROP TABLE users CASCADE CONSTRAINTS;

-- PostgreSQL: CASCADE로 참조하는 FK와 종속 객체 삭제
DROP TABLE users CASCADE;

-- MySQL: FK 검사 비활성화 후 삭제
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE users;
SET FOREIGN_KEY_CHECKS = 1;

CASCADE로 삭제하면 참조하는 외래키 제약만 삭제되고, 참조하는 테이블의 데이터는 삭제되지 않습니다(PostgreSQL의 CASCADE는 종속 객체(뷰 등)도 함께 삭제). 이 점을 혼동하지 않아야 합니다.

Oracle의 Flashback Drop

Oracle 10g부터는 DROP TABLE이 테이블을 완전히 삭제하지 않고 휴지통(Recycle Bin)에 넣습니다.

Oracle Flashback Drop
-- 삭제 (휴지통으로 이동)
DROP TABLE employees;

-- 휴지통 확인
SELECT object_name, original_name FROM recyclebin;

-- 복구
FLASHBACK TABLE employees TO BEFORE DROP;

-- 완전 삭제 (휴지통에 남기지 않음)
DROP TABLE employees PURGE;

-- 휴지통 비우기
PURGE RECYCLEBIN;

TRUNCATE TABLE — 데이터 전체 삭제

TRUNCATE TABLE은 테이블의 모든 데이터를 삭제하지만, 테이블 구조는 유지합니다. DDL이므로 자동 커밋되며 ROLLBACK할 수 없습니다.

TRUNCATE TABLE
-- 기본
TRUNCATE TABLE access_logs;

-- Oracle: 스토리지 반환 옵션
TRUNCATE TABLE access_logs DROP STORAGE;    -- 할당된 공간 반환 (기본)
TRUNCATE TABLE access_logs REUSE STORAGE;   -- 할당된 공간 유지

REUSE STORAGE는 같은 테이블에 곧 다시 데이터를 넣을 예정일 때 유용합니다. 공간을 반환했다가 다시 할당하는 오버헤드를 줄여줍니다.

DELETE vs TRUNCATE vs DROP 비교

구분DELETE FROMTRUNCATE TABLEDROP TABLE
분류DMLDDLDDL
동작조건에 맞는 행 삭제모든 행 삭제테이블 자체 삭제
구조 유지아니오
WHERE사용 가능불가불가
ROLLBACK가능불가 (대부분)불가
로그 기록행별로 기록 (Undo + Redo)최소한의 로그최소한의 로그
속도느림 (행 단위 처리)매우 빠름빠름
트리거 발생예 (DELETE 트리거)아니오해당 없음
AUTO_INCREMENT이어서 증가초기화해당 없음
외래키 참조 시참조 무결성 검사실패 (참조 있으면)CASCADE 필요
테이블 공간해제 안 됨 (HWM 유지)해제됨해제됨

TRUNCATE가 DELETE보다 빠른 이유는 근본적으로 다른 방식으로 동작하기 때문입니다. DELETE는 행을 하나씩 찾아 삭제하면서 각 행의 Undo 로그를 기록합니다. 100만 행이면 100만 번의 행 단위 처리가 필요합니다. 반면 TRUNCATE는 테이블이 사용하는 데이터 세그먼트의 할당을 한 번에 해제합니다.

HWM(High Water Mark) 개념
DELETE 후
  ┌──────────────────────────────────────────────┐
  │ [빈 공간] [빈 공간] [빈 공간] [빈 공간]      │ ← HWM 유지
  └──────────────────────────────────────────────┘
  → 데이터는 지워졌지만 할당된 공간은 그대로
  → 풀 스캔 시 빈 블록도 읽어야 함 (성능 저하)

TRUNCATE 후
  ┌──────┐
  │      │ ← HWM이 처음으로 되돌아감
  └──────┘
  → 할당된 공간이 반환됨
  → 풀 스캔 시 읽을 블록이 없음

이 HWM(High Water Mark) 문제 때문에, 대량 DELETE 후에도 테이블의 풀 스캔 성능이 개선되지 않는 경우가 있습니다. 이런 경우에는 테이블을 REBUILD하거나 SHRINK해야 합니다.


운영 중 스키마 변경 전략

운영 데이터베이스의 스키마 변경은 가장 위험한 작업 중 하나입니다. 변경의 종류에 따라 위험도가 크게 다릅니다.

위험도별 스키마 변경 분류

위험도 분류
🟢 낮은 위험 (대부분 안전):
  * NULL 허용 컬럼 추가 (기존 행에 영향 없음)
  * DEFAULT 값이 있는 컬럼 추가
  * 컬럼 이름 변경 (애플리케이션 코드 수정 필요)
  * 새로운 인덱스 생성 (Online DDL 사용 시)

🟡 중간 위험 (테스트 필수):
  * 컬럼 크기 변경 (확대는 안전, 축소는 위험)
  * NOT NULL 제약 추가 (기존 NULL 데이터 확인 필요)
  * 외래키 추가 (기존 데이터 정합성 확인 필요)
  * 인덱스 삭제 (의존하는 쿼리 확인 필요)

🔴 높은 위험 (점검 시간 고려):
  * 대용량 테이블 컬럼 타입 변경 (전체 행 재작성)
  * NOT NULL 컬럼 추가 without DEFAULT (기존 행 위반)
  * PRIMARY KEY 변경 (테이블 재구성)
  * 테이블 파티셔닝 적용

안전한 마이그레이션 절차

마이그레이션 체크리스트
1. 사전 조사
   □ 변경 대상 테이블의 데이터 건수 확인
   □ 관련 인덱스, 뷰, 트리거, 프로시저 목록 확인
   □ 외래키 참조 관계 확인
   □ 해당 테이블을 사용하는 애플리케이션 쿼리 목록

2. 개발 환경 테스트
   □ 동일 데이터 규모로 테스트 (10만 건 vs 1억 건은 다름)
   □ 변경 소요 시간 측정
   □ 락 발생 범위 확인
   □ 롤백 시나리오 테스트

3. 변경 SQL 준비
   □ 변경 SQL 작성 및 리뷰
   □ 롤백 SQL 작성 (복원용)
   □ 검증 SQL 작성 (변경 확인용)

4. 적용
   □ 서비스 영향 최소화 (점검 시간 활용 / 온라인 DDL)
   □ 변경 전 백업
   □ 변경 적용
   □ 검증 SQL 실행
   □ 애플리케이션 정상 동작 확인

5. 사후 관리
   □ 성능 모니터링 (새 인덱스, 변경된 쿼리 플랜)
   □ 에러 로그 확인
   □ 롤백 필요 시 준비된 SQL 실행

DBMS별 Online DDL 지원

Online DDL은 테이블에 락을 걸지 않고(또는 최소한의 락으로) 스키마를 변경하는 기능입니다.

MySQL Online DDL
-- MySQL 5.6+ Online DDL
ALTER TABLE employees ADD phone VARCHAR(20), ALGORITHM=INPLACE, LOCK=NONE;

-- ALGORITHM 옵션:
--   INPLACE: 테이블을 재구성하지 않고 변경 (빠름)
--   COPY:    임시 테이블에 복사 후 교체 (느리지만 확실)
--   INSTANT: 메타데이터만 변경 (MySQL 8.0+, 가장 빠름)

-- LOCK 옵션:
--   NONE:      락 없음 (DML 동시 실행 가능)
--   SHARED:    읽기 허용, 쓰기 차단
--   EXCLUSIVE: 읽기/쓰기 모두 차단
MySQL 8.0 INSTANT DDL
-- 컬럼 추가가 거의 즉시 완료 (메타데이터만 변경)
ALTER TABLE employees ADD phone VARCHAR(20), ALGORITHM=INSTANT;
-- 대용량 테이블도 1초 이내에 완료
Oracle Online DDL
-- 온라인 인덱스 생성
CREATE INDEX idx_emp_name ON employees(name) ONLINE;

-- 온라인 인덱스 재구성
ALTER INDEX idx_emp_name REBUILD ONLINE;

-- 온라인 테이블 재구성 (Oracle 12c+)
ALTER TABLE employees MOVE ONLINE;
PostgreSQL Online DDL
-- PostgreSQL은 대부분의 ALTER TABLE이 짧은 AccessExclusiveLock만 필요
-- 하지만 NOT NULL 추가 등은 전체 테이블 스캔 필요

-- NOT NULL 추가 시 CHECK 제약으로 대체 (큰 테이블에서 유용)
ALTER TABLE employees ADD CONSTRAINT chk_phone_nn CHECK (phone IS NOT NULL)
    NOT VALID;  -- 기존 데이터 검사 건너뛰기
-- 나중에 백그라운드에서 검증
ALTER TABLE employees VALIDATE CONSTRAINT chk_phone_nn;

무중단 스키마 변경 패턴 (Expand and Contract)

대규모 서비스에서는 Expand and Contract 패턴을 사용합니다. 이 패턴은 스키마 변경을 여러 단계로 나누어 각 단계에서 하위 호환성을 유지합니다.

Expand and Contract 패턴 예시
목표: 컬럼 이름을 name → full_name으로 변경

[기존 상태]
  테이블: employees (emp_id, name, email)
  애플리케이션: SELECT name FROM employees

[단계 1: Expand — 새 컬럼 추가]
  ALTER TABLE employees ADD full_name VARCHAR(200);
  → 트리거로 name ↔ full_name 동기화
  → 애플리케이션은 여전히 name 사용

[단계 2: Migrate — 데이터 이동]
  UPDATE employees SET full_name = name WHERE full_name IS NULL;
  → 배치로 처리

[단계 3: 애플리케이션 코드 변경]
  → name 대신 full_name을 사용하도록 배포
  → 이전 버전과 호환 유지

[단계 4: Contract — 이전 컬럼 삭제]
  → 트리거 제거
  → ALTER TABLE employees DROP COLUMN name;
  → 완료!

이 패턴은 각 단계에서 롤백이 가능하고, 서비스 중단 없이 스키마를 변경할 수 있다는 장점이 있습니다.


pt-online-schema-change (MySQL)

MySQL에서 대용량 테이블의 스키마를 변경할 때 가장 많이 사용되는 외부 도구입니다. Percona Toolkit에 포함되어 있습니다.

pt-online-schema-change 동작 원리
1. 새로운 구조의 빈 테이블 _employees_new 생성
2. 기존 테이블에 트리거 설치 (INSERT/UPDATE/DELETE 동기화)
3. 기존 데이터를 배치로 복사 (청크 단위)
4. 복사 완료 후 테이블 이름 교체 (RENAME TABLE)
5. 기존 테이블과 트리거 삭제

장점:
  * 복사 중에도 DML 가능 (서비스 중단 없음)
  * 락 시간이 매우 짧음 (RENAME은 메타데이터 변경만)

단점:
  * 트리거 오버헤드 (복사 중 DML 성능 저하)
  * 디스크 공간이 2배 필요 (원본 + 복사본)
  * FK가 있는 테이블에서는 사용이 복잡

Facebook의 gh-ost도 비슷한 역할을 하는 도구입니다. gh-ost는 트리거 대신 바이너리 로그를 사용하여 동기화하므로 트리거의 단점을 피할 수 있습니다.


ALTER TABLE 실무 예제

쇼핑몰 테이블 발전 과정

서비스가 성장하면서 테이블이 어떻게 변경되는지 실제 시나리오를 따라가 봅시다.

v1 → v2: 회원 등급 추가
-- 요구사항: 회원 등급 기능 추가
ALTER TABLE users ADD grade VARCHAR(10) DEFAULT 'BRONZE';
CREATE INDEX idx_users_grade ON users(grade);

-- 기존 VIP 고객 등급 업데이트 (매출 기준)
UPDATE users SET grade = 'GOLD'
WHERE user_id IN (
    SELECT user_id FROM orders
    GROUP BY user_id
    HAVING SUM(total_amount) >= 1000000
);
v2 → v3: 연락처 분리
-- 요구사항: 사용자당 여러 연락처 저장
-- 기존 phone 컬럼은 1개만 저장 가능

-- 1. 연락처 테이블 생성
CREATE TABLE user_contacts (
    contact_id  INT PRIMARY KEY AUTO_INCREMENT,
    user_id     INT NOT NULL REFERENCES users(user_id),
    contact_type VARCHAR(10) NOT NULL,  -- 'PHONE', 'FAX', 'MOBILE'
    contact_value VARCHAR(20) NOT NULL,
    is_primary  BOOLEAN DEFAULT FALSE
);

-- 2. 기존 데이터 이전
INSERT INTO user_contacts (user_id, contact_type, contact_value, is_primary)
SELECT user_id, 'PHONE', phone, TRUE
FROM users
WHERE phone IS NOT NULL;

-- 3. 기존 컬럼 삭제 (데이터 이전 확인 후)
ALTER TABLE users DROP COLUMN phone;
v3 → v4: 소프트 삭제 도입
-- 요구사항: 회원 탈퇴 시 데이터 보존 (법적 의무)
ALTER TABLE users ADD is_deleted BOOLEAN DEFAULT FALSE;
ALTER TABLE users ADD deleted_at TIMESTAMP NULL;

-- 기존 DELETE 로직을 UPDATE로 변경해야 함
-- 기존: DELETE FROM users WHERE user_id = ?;
-- 변경: UPDATE users SET is_deleted = TRUE, deleted_at = NOW() WHERE user_id = ?;

ALTER TABLE 성능에 영향을 주는 요소

요소영향대응
테이블 크기행 수가 많을수록 느림pt-osc, gh-ost 사용
인덱스 수인덱스가 많으면 재구성 시간 증가불필요 인덱스 정리 후 변경
외래키FK 검사 오버헤드FK_CHECKS 비활성화 (주의)
LOB 컬럼BLOB/CLOB 이동은 매우 느림별도 테이블로 분리 고려
리플리카반영 지연(replication lag) 발생리플리카 모니터링 필수

요약 정리

명령역할핵심 주의점
ALTER TABLE ADD컬럼/제약 추가NOT NULL 시 DEFAULT 필수
ALTER TABLE MODIFY컬럼 타입/크기/제약 변경기존 데이터 호환성 확인
ALTER TABLE DROP컬럼/제약 삭제종속 객체 확인 필수
DROP TABLE테이블 완전 삭제CASCADE 시 FK만 삭제
TRUNCATE TABLE데이터 전체 삭제DDL이므로 ROLLBACK 불가

스키마 변경의 핵심은 변경 자체가 아니라 안전한 변경입니다. 개발 환경에서 충분히 테스트하고, 운영 환경에서는 Online DDL이나 외부 도구를 활용하여 서비스 영향을 최소화하며, 항상 롤백 계획을 준비해 두어야 합니다. 특히 대용량 테이블에서의 스키마 변경은 반드시 DBA와 협의하여 진행하는 것이 좋습니다.

다음 장에서는 데이터를 실제로 조작하는 DML을 다루겠습니다.

목차