테이블 수정과 삭제
한 번 만든 테이블이 영원히 그대로 유지되는 일은 없습니다. 서비스가 성장하면 새로운 기능을 위해 컬럼을 추가해야 하고, 요구사항이 바뀌면 데이터 타입을 변경해야 하며, 불필요한 테이블은 정리해야 합니다. 이런 테이블 구조 변경을 담당하는 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 제약을 위반하게 되어 에러가 발생합니다.
-- 잘못된 방법 (기존 데이터 때문에 에러)
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에서는 이 기능을 지원하지 않습니다(항상 마지막에 추가됨).
-- 첫 번째 컬럼으로 추가
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 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)에 넣습니다.
-- 삭제 (휴지통으로 이동)
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 access_logs;
-- Oracle: 스토리지 반환 옵션
TRUNCATE TABLE access_logs DROP STORAGE; -- 할당된 공간 반환 (기본)
TRUNCATE TABLE access_logs REUSE STORAGE; -- 할당된 공간 유지REUSE STORAGE는 같은 테이블에 곧 다시 데이터를 넣을 예정일 때 유용합니다. 공간을 반환했다가 다시 할당하는 오버헤드를 줄여줍니다.
DELETE vs TRUNCATE vs DROP 비교
| 구분 | DELETE FROM | TRUNCATE TABLE | DROP TABLE |
|---|---|---|---|
| 분류 | DML | DDL | DDL |
| 동작 | 조건에 맞는 행 삭제 | 모든 행 삭제 | 테이블 자체 삭제 |
| 구조 유지 | 예 | 예 | 아니오 |
| WHERE | 사용 가능 | 불가 | 불가 |
| ROLLBACK | 가능 | 불가 (대부분) | 불가 |
| 로그 기록 | 행별로 기록 (Undo + Redo) | 최소한의 로그 | 최소한의 로그 |
| 속도 | 느림 (행 단위 처리) | 매우 빠름 | 빠름 |
| 트리거 발생 | 예 (DELETE 트리거) | 아니오 | 해당 없음 |
| AUTO_INCREMENT | 이어서 증가 | 초기화 | 해당 없음 |
| 외래키 참조 시 | 참조 무결성 검사 | 실패 (참조 있으면) | CASCADE 필요 |
| 테이블 공간 | 해제 안 됨 (HWM 유지) | 해제됨 | 해제됨 |
TRUNCATE가 DELETE보다 빠른 이유는 근본적으로 다른 방식으로 동작하기 때문입니다. DELETE는 행을 하나씩 찾아 삭제하면서 각 행의 Undo 로그를 기록합니다. 100만 행이면 100만 번의 행 단위 처리가 필요합니다. 반면 TRUNCATE는 테이블이 사용하는 데이터 세그먼트의 할당을 한 번에 해제합니다.
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 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: 읽기/쓰기 모두 차단-- 컬럼 추가가 거의 즉시 완료 (메타데이터만 변경)
ALTER TABLE employees ADD phone VARCHAR(20), ALGORITHM=INSTANT;
-- 대용량 테이블도 1초 이내에 완료-- 온라인 인덱스 생성
CREATE INDEX idx_emp_name ON employees(name) ONLINE;
-- 온라인 인덱스 재구성
ALTER INDEX idx_emp_name REBUILD ONLINE;
-- 온라인 테이블 재구성 (Oracle 12c+)
ALTER TABLE employees MOVE ONLINE;-- 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 패턴을 사용합니다. 이 패턴은 스키마 변경을 여러 단계로 나누어 각 단계에서 하위 호환성을 유지합니다.
목표: 컬럼 이름을 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에 포함되어 있습니다.
1. 새로운 구조의 빈 테이블 _employees_new 생성
2. 기존 테이블에 트리거 설치 (INSERT/UPDATE/DELETE 동기화)
3. 기존 데이터를 배치로 복사 (청크 단위)
4. 복사 완료 후 테이블 이름 교체 (RENAME TABLE)
5. 기존 테이블과 트리거 삭제
장점:
* 복사 중에도 DML 가능 (서비스 중단 없음)
* 락 시간이 매우 짧음 (RENAME은 메타데이터 변경만)
단점:
* 트리거 오버헤드 (복사 중 DML 성능 저하)
* 디스크 공간이 2배 필요 (원본 + 복사본)
* FK가 있는 테이블에서는 사용이 복잡Facebook의 gh-ost도 비슷한 역할을 하는 도구입니다. gh-ost는 트리거 대신 바이너리 로그를 사용하여 동기화하므로 트리거의 단점을 피할 수 있습니다.
ALTER TABLE 실무 예제
쇼핑몰 테이블 발전 과정
서비스가 성장하면서 테이블이 어떻게 변경되는지 실제 시나리오를 따라가 봅시다.
-- 요구사항: 회원 등급 기능 추가
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
);-- 요구사항: 사용자당 여러 연락처 저장
-- 기존 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;-- 요구사항: 회원 탈퇴 시 데이터 보존 (법적 의무)
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을 다루겠습니다.