DB 리팩토링으로 스키마 품질과 성능 개선하기

DB 리팩토링의 의미 보존 원칙, 데이터베이스 악취, 스키마·무결성·아키텍처 개선 방법과 적용 시 고려사항을 정리한다.

2026-08-14 · 최초 발행 2025-08-10

기능은 유지하고 데이터베이스 내부를 바꾸는 작업

DB 리팩토링은 시스템이 제공하는 기능과 데이터의 의미를 유지한 상태에서 데이터베이스 구조를 손보는 일이다. 스키마의 복잡도를 낮추고, 데이터 정합성과 성능, 유지보수성을 개선하는 데 목적이 있다.

스키마를 변경한다는 점에서는 단순한 구조 변경처럼 보일 수 있다. 그러나 기존 데이터의 의미와 애플리케이션의 동작을 보존해야 하므로, 변경 대상과 영향 범위를 함께 다뤄야 한다. 지속적인 개선과 변화 대응이 필요한 애자일 개발 환경에서도 이 작업이 필요하다.

구조가 문제를 드러내는 신호

하나의 컬럼에 여러 상태가 섞일 때

하나의 컬럼이 서로 다른 목적을 동시에 표현하면 컬럼의 뜻이 모호해진다. 예를 들어 status에 주문상태, 배송상태, 결제상태를 함께 저장하면 분석이 어려워지고 유지보수 복잡성이 커진다.

-- 다목적 컬럼의 예
CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    status VARCHAR(20) -- 주문상태, 배송상태, 결제상태 등 여러 상태를 하나의 컬럼에 저장
);

-- 리팩토링 후
CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    order_status VARCHAR(20),
    delivery_status VARCHAR(20),
    payment_status VARCHAR(20)
);

테이블 하나가 서로 다른 자산을 모두 담을 때

assets 테이블이 컴퓨터, 가구, 차량처럼 성격이 다른 자산 정보를 모두 보관하면 불필요한 NULL 값이 늘어난다. 무결성 제약을 걸기도 어렵고 조회 쿼리도 복잡해진다.

ASSETSintidPKstringtypestringcomputer_modelstringcomputer_cpustringfurniture_materialstringvehicle_modeldatevehicle_purchase_date

같은 데이터가 여러 위치에 저장되는 중복 데이터 역시 갱신 이상과 데이터 불일치, 저장 공간 낭비를 일으킨다.

컬럼에 복합 정보를 인코딩할 때

스마트 컬럼은 하나의 값 안에 여러 정보를 담는 방식이다. product_code에 카테고리, 브랜드, 일련번호를 함께 넣으면 검색 조건이 데이터 형식에 의존하고 비즈니스 로직과 저장 로직이 섞인다.

-- 스마트 컬럼 예시
SELECT * FROM products WHERE product_code LIKE 'ELEC-SAM-%';

-- 리팩토링 후
SELECT * FROM products WHERE category = 'ELEC' AND brand = 'SAM';

기존 구조를 건드리는 일을 계속 미루는 것도 경고 신호다. 변화에 대한 부담은 기술 부채를 키우고 구조를 점진적으로 악화시킨다.

불필요한 중간 테이블을 거치는 비정상적 참조 경로, 비즈니스 모델을 제대로 담지 못한 테이블 관계도 점검 대상이다. 이런 구조는 데이터 정합성을 해치고 복잡한 쿼리를 만든다. 조회와 삽입이 느려졌다면 과도한 인덱싱, 비효율적인 스키마, 정규화와 비정규화의 불균형도 함께 확인해야 한다.

리팩토링 직접 참조주문주문_상품상품

스키마와 데이터 품질을 다듬는 방식

구조 리팩토링은 과도하게 큰 테이블을 논리적으로 나누거나, 관련 컬럼을 적절한 테이블로 옮기고, 명명 규칙을 명확하게 적용하는 방식이다.

-- 테이블 분할 예시
-- 리팩토링 전: 거대한 사용자 테이블
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(100),
    email VARCHAR(100),
    address VARCHAR(200),
    city VARCHAR(50),
    postal_code VARCHAR(20),
    country VARCHAR(50),
    phone VARCHAR(20)
);

-- 리팩토링 후: 사용자와 주소 정보 분리
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(100),
    email VARCHAR(100),
    phone VARCHAR(20)
);

CREATE TABLE addresses (
    id INT PRIMARY KEY,
    user_id INT REFERENCES users(id),
    address VARCHAR(200),
    city VARCHAR(50),
    postal_code VARCHAR(20),
    country VARCHAR(50)
);

데이터 품질 개선에서는 NULL 값을 줄이기 위한 기본값 도입, 적절한 데이터 타입 적용, CHECK 제약조건을 통한 도메인 무결성 강화가 대상이 된다.

-- 데이터 품질 개선 예시
-- 리팩토링 전
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    price VARCHAR(20), -- 문자열로 가격 저장
    status CHAR(1) -- 'A', 'I', 'D' 등의 코드 사용
);

-- 리팩토링 후
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL, -- NULL 방지
    price DECIMAL(10,2) NOT NULL, -- 적절한 데이터 타입
    status VARCHAR(10) CHECK (status IN ('Active', 'Inactive', 'Discontinued')) -- 의미 명확화
);

테이블 관계를 정확하게 유지하려면 외래 키 제약조건을 추가하고 캐스케이드 동작을 정의하며 고아 레코드를 제거한다.

-- 참조 무결성 강화 예시
-- 리팩토링 전: 제약조건 없음
CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT
);

-- 리팩토링 후: 외래 키 제약조건 추가
ALTER TABLE orders
ADD CONSTRAINT fk_customer
FOREIGN KEY (customer_id) REFERENCES customers(id)
ON DELETE CASCADE;

외부 프로그램과 데이터베이스의 접점을 바꾸는 일도 리팩토링에 포함된다. 복잡한 쿼리를 뷰로 감추고, API 레이어로 직접적인 테이블 접근을 제한하거나, 도메인별 데이터베이스를 분리하는 마이크로서비스 구조를 적용할 수 있다.

-- 아키텍처 개선 예시: 뷰 생성
CREATE VIEW order_summary AS
SELECT o.id, c.name AS customer_name, o.order_date,
       SUM(oi.quantity * p.price) AS total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON oi.product_id = p.id
GROUP BY o.id, c.name, o.order_date;

저장 프로시저, 트리거, 함수는 코드 중복을 제거하고 기능별로 나누며 예외 처리를 강화하는 방향으로 바꾼다.

-- 기능 변환 예시: 저장 프로시저 개선
-- 리팩토링 전: 거대한 저장 프로시저
CREATE PROCEDURE process_order(...)
BEGIN
    -- 수백 줄의 복잡한 로직
END;

-- 리팩토링 후: 모듈화된 저장 프로시저
CREATE PROCEDURE validate_order(...)
BEGIN
    -- 주문 유효성 검증 로직
END;

CREATE PROCEDURE calculate_totals(...)
BEGIN
    -- 금액 계산 로직
END;

CREATE PROCEDURE process_order(...)
BEGIN
    CALL validate_order(...);
    CALL calculate_totals(...);
    -- 나머지 로직
END;

영향 분석부터 검증과 배포까지

변경은 필요성 식별에서 시작해 영향 분석, 테스트 계획, 백업 및 롤백 계획, 실행과 테스트, 문서화 및 배포로 이어진다. 테스트를 통과하지 못하면 롤백한 뒤 영향 분석 단계로 돌아간다.

YesNo1. 리팩토링 필요성 식별2. 영향 분석3. 테스트 계획 수립4. 백업 롤백 계획5. 리팩토링 실행6. 테스트 수행테스트 통과?7. 문서화 배포롤백 실행

의미 보존은 이 과정의 기준이다. 데이터 손실을 막고 기존 의미를 바꾸지 않아야 하며, DB Regression Test를 반드시 수행해야 한다.

복원 가능한 시나리오와 검증 체계를 마련하고 단계적으로 적용하면 롤백 위험을 줄일 수 있다. 리팩토링 전후의 성능을 비교 측정하고, 인덱스 재구성과 대용량 데이터 처리 전략도 검토해야 한다. ORM 매핑, API 호환성, 클라이언트 코드에 미치는 영향 역시 변경 전에 분석한다.

전자상거래와 금융 시스템에서의 변경

전자상거래 시스템에서는 모든 상품 정보를 단일 테이블에 저장하고, 주문 상태를 하나의 컬럼 코드로 표현하며, 주소 정보를 여러 테이블에 중복 저장하는 문제가 있었다. 상품 테이블을 카테고리별로 분리하고, 주문 상태를 세분화해 별도 테이블로 정규화했으며, 주소 정보를 별도 테이블로 추출해 참조 관계를 설정했다.

그 결과 쿼리 성능은 35% 향상됐고, 데이터 일관성 문제는 90% 감소했으며, 신규 기능 개발 속도는 50% 증가했다.

hasplacescontainsreferenceshasbelongs_toCUSTOMERSADDRESSESORDERSORDER_ITEMSPRODUCTSORDER_STATUSCATEGORIES

금융 시스템 사례에서는 계좌 정보와 거래 내역이 단일 테이블에 있었고, 복잡한 저장 프로시저와 비효율적인 조인 구조가 유지보수와 성능을 저해했다. 계좌와 거래 내역 테이블을 분리하고 저장 프로시저를 모듈화했으며, 인덱스를 최적화하고 뷰를 도입했다. 월말 결산 시간은 60% 단축됐고 시스템 안정성과 감사 추적 기능도 향상됐다.

DB 리팩토링은 구조를 바꾸는 작업인 동시에 데이터베이스 품질을 지속적으로 관리하는 방식이다. 악취를 조기에 식별하고, 의미 보존·테스트·롤백 계획을 변경 흐름 안에 포함해야 안전하게 이어갈 수 있다.

데이터베이스 리팩토링DB Smell스키마 개선참조 무결성성능 최적화