SQL 개발자(SQLD)

SQL 개발자(SQLD) 시험 노트개념 정리18 MIN

정규화와 반정규화

SQLD 1과목의 다섯째 자리입니다. 함수적 종속성에서 출발해 제1·제2·제3정규형과 BCNF가 각각 무엇을 걷어내는지, 정규화하지 않으면 생기는 이상 현상 셋, 그리고 반정규화의 대상과 기법까지 정리합니다.

앞 노트에서 식별자를 정했습니다. 정규화는 그 식별자를 기준으로 「이 속성이 무엇에 딸려 있는가」를 따져 테이블을 쪼개는 일입니다. 1과목에서 두세 문항이 나오고, 표를 주고 몇 정규형인지 고르게 하거나 반정규화 기법의 이름을 묻는 형태가 대부분입니다.

함수적 종속성

함수적 종속성은 한 속성의 값이 정해지면 다른 속성의 값이 하나로 정해지는 관계입니다. 사원번호를 알면 사원명이 하나로 정해지므로 「사원번호 → 사원명」으로 씁니다. 화살표 왼쪽을 결정자, 오른쪽을 종속자라고 부릅니다.

정규화는 이 화살표를 읽는 작업입니다. 어느 정규형에 걸리는지는 「무엇이 무엇을 결정하는가」만으로 판정되고, 데이터가 몇 건인지는 상관이 없습니다.

완전 함수 종속과 부분 함수 종속

결정자가 복합키일 때만 생기는 구별입니다. 종속자가 복합키 전체에 딸려 있으면 완전 함수 종속이고, 복합키의 일부만으로도 정해지면 부분 함수 종속입니다.

수강 테이블이 (학번, 과목코드)를 주식별자로 갖고 학생명·성적을 함께 들고 있다고 하면 이렇게 갈립니다.

종속 종류 이유
(학번, 과목코드) → 성적 완전 함수 종속 둘이 다 있어야 성적이 하나로 정해진다
학번 → 학생명 부분 함수 종속 과목코드 없이 학번만으로 정해진다

이행 함수 종속

A → B이고 B → C이면 A → C도 성립하는데, 이때 A → C를 이행 함수 종속이라고 합니다. 사원 테이블이 사원번호·부서코드·부서명을 들고 있으면 「사원번호 → 부서코드 → 부서명」이 되어 부서명이 사원번호에 이행적으로 딸립니다. 가운데의 부서코드가 키가 아닌 일반 속성이라는 것이 문제의 지점입니다.

이상 현상

정규화하지 않은 테이블에서 데이터를 넣고 고치고 지울 때 생기는 부작용을 이상 현상이라고 합니다. 셋 모두 「한 테이블에 두 가지 주제가 섞여 있다」는 한 가지 원인에서 나옵니다.

세 가지 이상

위의 사원 테이블(사원번호, 사원명, 부서코드, 부서명)로 보면 이렇습니다.

이상 무슨 일이 생기나
삽입 이상 사원이 아직 없는 새 부서를 등록하려면 사원 행을 억지로 만들어야 한다
갱신 이상 부서명이 바뀌면 그 부서 사원 행을 전부 고쳐야 하고, 일부만 고치면 값이 갈린다
삭제 이상 마지막 사원을 지우면 부서 정보까지 함께 사라진다

세 이상 중 시험에 가장 자주 나오는 것은 갱신 이상입니다. 「같은 사실이 여러 행에 중복 저장되어 있기 때문」이 원인이고, 부서를 별도 테이블로 떼면 부서명이 한 곳에만 남아 셋이 함께 사라집니다.

정규형

정규형은 단계마다 정확히 한 가지를 걷어냅니다. 무엇을 걷어내는지만 외우면 표를 보고 판정할 수 있습니다.

제1정규형

모든 속성의 값이 더 쪼갤 수 없는 원자값이어야 합니다. 한 칸에 「영어, 수학, 과학」처럼 여러 값이 들어 있거나 과목1·과목2·과목3처럼 반복되는 컬럼이 있으면 제1정규형이 아닙니다. 값을 행으로 풀어 해결합니다.

제2정규형

제1정규형을 만족하면서 부분 함수 종속을 없앤 상태입니다. 위의 수강 테이블에서 학생명은 학번만으로 정해지므로 학생 테이블로 떼어냅니다. 주식별자가 단일 속성이면 부분 함수 종속이 성립할 수 없으므로 제1정규형만 만족하면 제2정규형은 자동입니다.

-- 제2정규형 위반: 학생명이 학번에만 딸려 있다
CREATE TABLE 수강 (
  학번     VARCHAR2(10),
  과목코드 VARCHAR2(10),
  학생명   VARCHAR2(30),
  성적     NUMBER,
  PRIMARY KEY (학번, 과목코드)
);

-- 분해 후
CREATE TABLE 학생 (학번 VARCHAR2(10) PRIMARY KEY, 학생명 VARCHAR2(30));
CREATE TABLE 수강 (
  학번     VARCHAR2(10) REFERENCES 학생(학번),
  과목코드 VARCHAR2(10),
  성적     NUMBER,
  PRIMARY KEY (학번, 과목코드)
);

제3정규형

제2정규형을 만족하면서 이행 함수 종속을 없앤 상태입니다. 사원 테이블에서 부서명을 부서 테이블로 떼는 것이 여기입니다. 「기본키가 아닌 속성이 기본키가 아닌 다른 속성을 결정하고 있으면 제3정규형 위반」으로 읽으면 판정이 빠릅니다.

BCNF

BCNF는 제3정규형을 강화한 것으로, 테이블의 모든 결정자가 후보키여야 합니다. 후보키가 아닌 속성이 무언가를 결정하고 있으면 제3정규형은 통과해도 BCNF는 걸립니다.

「수강(학번, 과목코드, 교수)」에서 한 교수가 한 과목만 가르친다면 「교수 → 과목코드」가 성립하는데, 교수는 후보키가 아닙니다. 종속자인 과목코드가 주식별자의 일부라 제3정규형에는 안 걸리지만 BCNF에는 걸립니다. 이 상황이 BCNF 문항의 거의 전부입니다.

반정규화

반정규화는 조회 성능을 얻으려고 정규화된 구조를 일부러 되돌리는 설계입니다. 정규화를 안 한 것과는 다릅니다 — 정규화를 끝낸 뒤 근거를 갖고 되돌리는 것이라, 중복이 생긴다는 사실을 알고 그 중복을 관리할 방법까지 함께 정합니다.

반정규화의 대상

아무 데나 하지 않습니다. 자주 조회되는데 처리 범위가 넓어 매번 조인·집계가 필요한 자리, 테이블에 데이터가 많고 조회 범위가 넓은 자리, 통계처럼 계산 비용이 큰 자리가 대상입니다. 반대로 갱신이 잦은 자리는 피합니다 — 중복된 값을 동기화하는 비용이 조회에서 번 것을 넘습니다.

테이블 반정규화

기법 무엇을 하나
테이블 병합 자주 함께 조회되는 1:1 또는 1:M 테이블을 하나로 합친다
테이블 분할 행 기준(수평) 또는 컬럼 기준(수직)으로 쪼개 접근 범위를 줄인다
테이블 추가 중복 테이블·통계 테이블·이력 테이블·부분 테이블을 따로 만든다

컬럼과 관계 반정규화

컬럼 쪽은 중복 컬럼 추가, 파생 컬럼 추가, 이력 테이블의 최신값 컬럼 추가가 대표적입니다. 주문에 주문금액합계를 미리 두면 주문상세를 매번 더하지 않아도 되지만, 주문상세가 바뀔 때마다 그 값을 다시 계산해 주어야 합니다.

관계 쪽은 중복관계 추가입니다. A–B–C로 이어진 구조에서 A와 C를 직접 잇는 관계를 하나 더 만들어 중간 테이블을 건너뛰게 합니다. 데이터 자체는 늘지 않고 조인 단계만 줄어드는 기법이라 부작용이 비교적 작습니다.

정규화와 조회 성능

정규화하면 성능이 나빠진다는 말이 흔한데, 절반만 맞습니다. 정규화는 데이터를 중복 없이 나누는 것이고 성능은 조회 형태에 따라 양쪽으로 다 움직입니다.

느려지는 자리

여러 테이블의 속성을 한꺼번에 봐야 하는 조회입니다. 사원명과 부서명을 함께 뽑으려면 조인이 한 번 더 붙고, 이런 조회가 잦으면 그 비용이 쌓입니다. 반정규화가 겨냥하는 자리가 정확히 여기입니다.

빨라지는 자리

테이블이 쪼개지면 한 행의 길이가 짧아져 같은 크기의 블록에 더 많은 행이 들어갑니다. 부서명 없이 사원번호·사원명만 읽으면 되는 조회는 읽어야 할 블록 수가 줄어 오히려 빨라집니다. 입력·수정·삭제도 같은 값을 한 곳에서만 고치면 되므로 빨라집니다.

그래서 「정규화하면 성능이 나빠진다」는 보기는 틀린 문장으로 출제됩니다. 정확한 문장은 **「정규화는 조회 성능을 떨어뜨릴 수도 있고 올릴 수도 있으며, 입력·수정·삭제 성능은 대체로 올린다」**입니다.

연습 문제

  1. 다음 중 함수적 종속성에 대한 설명으로 옳지 않은 것은?
    ① 「A → B」에서 A를 결정자, B를 종속자라고 한다
    ② 결정자의 값이 정해지면 종속자의 값이 하나로 정해진다
    ③ 데이터가 많아지면 함수적 종속성이 달라질 수 있다
    ④ 「A → B」이고 「B → C」이면 「A → C」가 성립한다
    ③. 함수적 종속성은 업무 규칙에서 나오는 성질이라 저장된 데이터 건수와 무관합니다.
  2. 다음 테이블이 위반하는 정규형은?
    「수강(학번, 과목코드, 학생명, 성적) — 기본키는 (학번, 과목코드)이고 학번은 학생명을 결정한다」
    ① 제1정규형
    ② 제2정규형
    ③ 제3정규형
    ④ BCNF
    ②. 학생명이 복합키의 일부인 학번만으로 정해지므로 부분 함수 종속입니다. 이것을 없앤 상태가 제2정규형입니다.
  3. 다음 테이블이 위반하는 정규형은?
    「사원(사원번호, 사원명, 부서코드, 부서명) — 기본키는 사원번호이고 부서코드는 부서명을 결정한다」
    ① 제1정규형
    ② 제2정규형
    ③ 제3정규형
    ④ 위반하지 않는다
    ③. 주식별자가 단일 속성이라 부분 함수 종속은 없지만, 키가 아닌 부서코드가 부서명을 결정하는 이행 함수 종속이 남아 있습니다.
  4. 이상 현상에 대한 설명으로 옳은 것은?
    ① 삽입 이상은 데이터를 지울 때 함께 지워지는 현상이다
    ② 갱신 이상은 중복된 값 중 일부만 고쳐 값이 갈리는 현상이다
    ③ 삭제 이상은 새 데이터를 넣을 수 없는 현상이다
    ④ 세 이상은 각각 원인이 다르다
    ②. ①과 ③은 서로 설명이 바뀌었고, ④는 셋 다 「한 테이블에 두 주제가 섞여 중복 저장된다」는 같은 원인에서 나옵니다.
  5. 다음 SQL이 만드는 테이블에 대한 설명으로 옳은 것은?
    CREATE TABLE 강의 (
      학번     VARCHAR2(10),
      과목코드 VARCHAR2(10),
      교수     VARCHAR2(30),
      PRIMARY KEY (학번, 과목코드)
    );
    「한 교수는 한 과목만 가르치고, 한 과목은 여러 교수가 가르칠 수 있다」
    ① 제2정규형을 위반한다
    ② 제3정규형은 만족하지만 BCNF를 위반한다
    ③ BCNF까지 모두 만족한다
    ④ 제1정규형을 위반한다
    ②. 「교수 → 과목코드」가 성립하는데 교수는 후보키가 아닙니다. 다만 종속자인 과목코드가 주식별자의 일부라 제3정규형 위반은 아니고, 모든 결정자가 후보키여야 하는 BCNF에만 걸립니다.
  6. 반정규화의 대상으로 가장 적절하지 않은 자리는?
    ① 조회 범위가 넓어 매번 여러 테이블을 조인해야 하는 자리
    ② 계산 비용이 큰 통계 값을 자주 조회하는 자리
    ③ 값이 수시로 갱신되는 자리
    ④ 데이터가 많고 처리 범위가 넓은 자리
    ③. 갱신이 잦으면 중복된 값을 맞추는 비용이 조회에서 번 것을 넘습니다.
  7. 반정규화 기법과 설명이 잘못 짝지어진 것은?
    ① 중복관계 추가 — 이어진 테이블을 건너뛰도록 관계를 하나 더 만든다
    ② 파생 컬럼 추가 — 계산해야 얻는 값을 미리 컬럼으로 둔다
    ③ 테이블 수직 분할 — 자주 쓰는 컬럼과 아닌 컬럼을 나눠 접근 범위를 줄인다
    ④ 테이블 병합 — 한 테이블을 행 기준으로 여러 테이블로 나눈다
    ④. 행 기준으로 나누는 것은 수평 분할입니다. 병합은 자주 함께 조회되는 테이블을 하나로 합치는 기법입니다.
  8. 정규화와 성능에 대한 설명으로 옳은 것은?
    ① 정규화하면 모든 조회가 느려진다
    ② 정규화하면 한 행의 길이가 짧아져 빨라지는 조회도 있다
    ③ 정규화는 입력·수정·삭제 성능을 떨어뜨린다
    ④ 반정규화는 정규화를 하지 않는 것을 말한다
    ②. 테이블이 쪼개지면 같은 블록에 더 많은 행이 들어가므로 필요한 컬럼만 읽는 조회는 오히려 빨라집니다. ③은 반대이고, ④는 정규화를 끝낸 뒤 근거를 갖고 되돌리는 것이 반정규화입니다.

여기까지가 1과목입니다. 다음 자리부터는 2과목으로 넘어가 관계형 데이터베이스의 용어와 SQL 문장의 갈래를 정리합니다. 지금까지 모델로 그려 온 엔터티·속성·관계가 테이블·컬럼·외래키라는 이름으로 다시 나오므로, 1과목 용어를 한 번 더 훑고 넘어가면 2과목 첫 절이 가볍습니다.

SQL 개발자(SQLD) 시험 노트 전체 보기