SQL 전문가(SQLP)

SQL 전문가(SQLP) 시험 노트개념 정리18 MIN

엔터티와 속성, 관계 읽기

SQLP 1과목의 둘째 자리입니다. 엔터티의 여섯 가지 특징과 두 축의 분류, 기본·설계·파생 속성과 단일값·다중값 속성, 도메인과 명명 규칙, 그리고 페어링·관계 차수·카디널리티·선택성을 정리합니다.

앞 노트에서 모델이 세 단계로 내려오는 길과 식별자를 봤습니다. 이 노트는 그 모델을 이루는 세 재료 — 엔터티, 속성, 관계를 하나씩 열어 봅니다. SQLP에서 이 셋을 묻는 방식은 정의를 되묻는 것이 아니라 ERD 한 장을 주고 그 안에서 몇 건이 나오는지, 어느 조인이 필요한지를 묻는 쪽입니다. 그래서 낱말의 뜻보다 그 낱말이 SQL의 어느 부분으로 내려앉는지를 함께 붙들어야 합니다.

엔터티

여섯 가지 특징

엔터티는 업무가 관리하려는 대상이고, 그 대상 하나하나의 실제 값이 인스턴스입니다. 「사원」이 엔터티라면 「사번 1001번 김팔딘」이 인스턴스입니다. 무엇이 엔터티가 될 수 있는지는 여섯 가지로 정리됩니다.

특징 뜻
업무에서 필요로 한다 그 업무가 실제로 쓰는 정보여야 한다
유일한 식별자가 있다 인스턴스를 하나로 특정할 수 있어야 한다
인스턴스가 둘 이상이다 하나뿐이면 상수이지 엔터티가 아니다
속성을 갖는다 속성이 없으면 저장할 것이 없다
관계를 하나 이상 갖는다 다른 엔터티와 이어지지 않으면 고립된 섬이다
업무 프로세스가 이용한다 아무도 읽고 쓰지 않으면 남길 이유가 없다

여섯 중 시험에서 가장 자주 반례로 나오는 것이 세 번째와 다섯 번째입니다. 「회사 정보」처럼 한 행뿐인 것, 그리고 코드값을 담아 두었지만 어디서도 참조하지 않는 표가 그렇습니다. 다만 관계가 없다는 이유만으로 무조건 지우지는 않습니다 — 통계용 스냅샷처럼 의도적으로 끊어 둔 것도 있어 업무를 먼저 확인합니다.

인스턴스와 엔터티

논리 모델의 엔터티는 물리 모델에서 테이블이 되고, 인스턴스는 그 테이블의 행이 되며, 속성은 칼럼이 됩니다. 셋은 나란한 세 낱말이 아니라 같은 대상을 서로 다른 층에서 부르는 이름입니다.

논리 모델 물리 모델
엔터티 테이블
인스턴스 행(row)
속성 칼럼
식별자 기본키

엔터티의 분류

물리적 형태에 따라

손으로 만질 수 있는 대상이면 유형 엔터티(사원, 상품, 창고), 개념으로만 존재하면 개념 엔터티(부서, 조직, 보험상품), 업무를 하다 발생한 사건이면 사건 엔터티(주문, 청구, 입금)입니다.

이 축은 그냥 이름 붙이기로 끝나지 않습니다. 사건 엔터티는 시간이 흐를수록 행이 쌓이지만 유형·개념 엔터티는 거의 늘지 않습니다. 조인 순서를 짐작할 때 「작은 쪽부터」의 그 작은 쪽이 대개 유형·개념 엔터티입니다.

발생 시점에 따라

다른 엔터티에 기대지 않고 스스로 생기면 기본 엔터티(사원, 부서, 고객, 상품), 기본 엔터티에서 발생하며 업무의 중심이 되면 중심 엔터티(계약, 주문, 매출), 둘 이상의 부모에서 발생해 주로 이력이나 목록을 담으면 행위 엔터티(주문상세, 계약변경이력)입니다.

갈래 어디서 생기나 주식별자의 모양
기본 엔터티 스스로 단일식별자가 흔하다
중심 엔터티 기본 엔터티에서 자기 번호 하나
행위 엔터티 둘 이상의 부모에서 복합식별자가 흔하다

분류가 모델에 남기는 것

두 축은 서로 독립입니다. 「주문」은 물리적 형태로는 사건 엔터티이고 발생 시점으로는 중심 엔터티입니다. 두 축을 함께 읽으면 그 엔터티가 앞으로 얼마나 커질지, 주식별자가 몇 칼럼이 될지가 미리 보입니다. 행위 엔터티가 복합식별자를 갖는 이유는 여러 부모의 키를 함께 물려받기 때문입니다.

속성

기본·설계·파생

속성은 엔터티가 갖는, 더 이상 쪼갤 수 없는 값입니다. 어디서 왔는지에 따라 셋으로 갈립니다.

  • 기본 속성: 업무에서 그대로 가져온 값. 회원명, 주문일자.
  • 설계 속성: 업무에는 없지만 관리를 위해 만든 값. 상품코드, 주문번호처럼 일련번호로 부여한 것.
  • 파생 속성: 다른 속성에서 계산해 만든 값. 주문금액 합계, 재고 수량.

파생 속성이 튜닝에서 늘 논쟁거리입니다. 저장해 두면 조회는 빠르지만 원본이 바뀔 때마다 다시 계산해 넣어야 하고, 그 갱신을 한 곳이라도 빠뜨리면 값이 어긋납니다. 그래서 파생 속성은 계산 규칙과 갱신 시점을 함께 적어 두지 않으면 만들지 않습니다.

단일값과 다중값

한 인스턴스에 값이 하나만 대응하면 단일값 속성, 여럿이 대응하면 다중값 속성입니다. 회원의 생년월일은 단일값이고, 회원의 전화번호는 흔히 다중값입니다.

다중값 속성은 그대로 두면 제1정규형을 어깁니다. 값을 쉼표로 이어 한 칼럼에 넣는 순간 그 칼럼은 인덱스로 찾을 수 없게 되고, 한 번호로 회원을 찾으려면 LIKE '%010-1234%' 같은 조건을 쓰게 됩니다. 해소는 별도 엔터티로 빼는 것입니다.

-- 다중값을 한 칼럼에 넣은 모델: 인덱스를 못 탄다
SELECT * FROM 회원 WHERE 전화번호목록 LIKE '%010-1234-5678%';

-- 별도 엔터티로 뺀 모델: 전화번호 인덱스를 탄다
SELECT m.*
  FROM 회원 m
  JOIN 회원전화 p ON p.회원번호 = m.회원번호
 WHERE p.전화번호 = '010-1234-5678';

도메인

도메인은 한 속성이 가질 수 있는 값의 범위입니다. 자료형과 길이, 허용하는 값의 목록까지가 도메인입니다. 「주문상태」의 도메인이 접수·결제완료·배송중·완료·취소 다섯이라면, 그 밖의 값이 들어오는 순간 모든 상태별 집계가 틀어집니다.

도메인을 지키는 방법은 물리 모델에서 셋입니다 — CHECK 제약, 코드 테이블과 외래키, 그리고 응용 프로그램의 검증입니다. 앞의 둘은 데이터베이스가 지켜 주고 마지막 하나는 지켜 주지 않습니다.

속성의 명명

같은 뜻의 속성이 테이블마다 다른 이름으로 있으면 조인 조건을 쓸 때마다 이름을 확인해야 합니다. 명명 규칙은 셋으로 요약됩니다 — 업무에서 쓰는 용어를 쓰고, 서술식 표현을 피하며, 같은 뜻이면 어느 엔터티에서나 같은 이름을 씁니다. 마지막 것이 지켜지면 USING 절이나 자연 조인이 안전해지고, 지켜지지 않으면 그 문법은 오히려 위험해집니다.

관계

페어링

관계는 두 엔터티의 인스턴스끼리 맺어진 짝의 묶음입니다. 그 짝 하나하나를 페어링이라 부릅니다. 관계는 페어링의 집합이지 페어링 그 자체가 아니라는 것이 요점입니다 — 「사원과 부서는 소속 관계다」는 모델의 선 한 줄이고, 「김팔딘은 개발부에 속한다」는 그 선을 타고 만들어진 페어링 하나입니다.

관계 차수

관계 차수는 그 관계에 참여하는 엔터티의 개수입니다. 두 엔터티가 참여하면 이항 관계, 셋이면 삼항 관계이고, 한 엔터티가 자기 자신과 맺으면 재귀 관계입니다. 조직도의 「상위부서」나 사원의 「관리자」가 재귀 관계이고, SQL에서는 셀프 조인이나 계층형 질의로 풀립니다.

카디널리티와 선택성

카디널리티는 한쪽 인스턴스 하나에 다른 쪽 인스턴스가 몇 개까지 대응하는지입니다. 관계 차수가 참여하는 엔터티의 수를 세는 값이라면 카디널리티는 참여하는 인스턴스의 수를 세는 값입니다. 둘 다 「관계의 크기」를 말하지만 세는 대상이 다릅니다.

카디널리티는 1:1, 1:M, M:N 셋으로 적습니다. 이 가운데 M:N은 관계형 데이터베이스가 그대로 담지 못합니다. 어느 쪽에 외래키를 두어도 값이 여럿이 되어 다중값 속성이 되기 때문입니다. 그래서 두 키를 함께 갖는 엔터티를 하나 세워 1:M 둘로 쪼개는데, 이것을 M:N 해소라 하고 그렇게 생긴 엔터티가 앞에서 본 행위 엔터티입니다. 해소하고 나면 조인이 한 번에서 두 번으로 늘어납니다.

선택성은 참여가 반드시 일어나야 하는지를 말합니다. 반드시 참여하면 필수 관계, 참여하지 않아도 되면 선택 관계입니다. 필수 관계는 물리 모델에서 외래키 칼럼의 NOT NULL 제약으로 내려앉고, 선택 관계는 NULL을 허용하는 외래키로 남습니다.

모델에 적힌 것 물리 모델 SQL에서
1:M 카디널리티 자식에 외래키 조인 결과 건수가 자식 건수까지 늘어난다
M:N 카디널리티 교차 엔터티로 해소 조인이 두 번
필수 관계 외래키 NOT NULL 내부 조인으로 충분
선택 관계 외래키 NULL 허용 아우터 조인이 필요할 수 있다

마지막 줄이 실전에서 가장 자주 실점하는 자리입니다. 선택 관계를 내부 조인으로 쓰면 값이 없는 행이 조용히 사라지고, 그 결과가 집계로 넘어가면 합계가 틀어집니다. 오류가 아니라 건수만 달라지는 형태로 나타나 눈에 잘 띄지 않습니다.

연습 문제

  1. 다음 중 엔터티로 세우기에 가장 부적절한 것은?
    ① 회원
    ② 주문
    ③ 본사 사업자 정보(행이 하나뿐이고 변하지 않는다)
    ④ 상품
    ③. 인스턴스가 둘 이상이어야 한다는 조건을 만족하지 못합니다. 값이 하나뿐이고 변하지 않으면 그것은 엔터티가 아니라 상수에 가깝습니다.
  2. 「계약변경이력」을 발생 시점으로 분류하면?
    ① 기본 엔터티
    ② 중심 엔터티
    ③ 행위 엔터티
    ④ 개념 엔터티
    ③. 계약과 변경 사유 같은 둘 이상의 부모에서 발생하며 이력을 담습니다. ④는 물리적 형태 축의 값이라 발생 시점 분류의 답이 될 수 없습니다.
  3. 파생 속성에 해당하는 것은?
    ① 회원가입일자
    ② 주문번호
    ③ 주문상세의 수량
    ④ 주문 총액(주문상세 금액의 합)
    ④. 다른 속성에서 계산해 만든 값입니다. ①·③은 업무에서 그대로 가져온 기본 속성이고, ②는 관리를 위해 부여한 설계 속성입니다.
  4. 회원 5명이 있고 각 회원의 전화번호가 순서대로 1개, 2개, 3개, 0개, 2개다. 회원 전화번호를 별도 엔터티로 뺀 뒤 회원과 회원전화를 내부 조인하면 결과는 몇 건인가?
    ① 5건
    ② 8건
    ③ 9건
    ④ 10건
    ②. 내부 조인은 짝이 있는 페어링만 남기므로 전화번호 건수의 합이 그대로 결과 건수가 됩니다. 1+2+3+0+2=81 + 2 + 3 + 0 + 2 = 8 건입니다. 전화번호가 없는 회원 한 명은 사라지고, 그 회원까지 살리려면 아우터 조인이 필요해 9건이 됩니다.
  5. 관계 차수와 카디널리티에 대한 설명으로 옳은 것은?
    ① 관계 차수는 1:1, 1:M, M:N 중 하나로 적는다
    ② 카디널리티는 관계에 참여하는 엔터티의 개수다
    ③ 재귀 관계는 관계 차수를 말할 때 쓰는 개념이다
    ④ 선택성과 카디널리티는 같은 것을 다르게 부른 이름이다
    ③. 재귀 관계는 한 엔터티가 자기 자신과 맺는 관계이므로 참여 엔터티를 세는 관계 차수 쪽 개념입니다. ①과 ②는 두 낱말을 서로 바꿔 놓은 설명이고, ④는 선택성이 참여의 필수 여부를 말한다는 점에서 틀립니다.
  6. 회원과 배송지가 선택 관계인 모델에서, 회원별 배송지 개수를 세는 SQL을 내부 조인으로 작성했다. 이때 결과가 업무 요구와 어긋나는 지점을 쓰고 어떻게 고쳐야 하는지 함께 서술하시오.
    배송지를 한 건도 등록하지 않은 회원이 결과에서 통째로 사라집니다. 「모든 회원의 배송지 개수」를 요구했다면 그 회원들이 0건으로 나와야 하는데 아예 행이 없으므로, 회원 수를 함께 세면 실제보다 작은 값이 나옵니다. 고치는 방법은 회원을 기준으로 한 아우터 조인으로 바꾸고 개수는 COUNT(b.배송지번호)처럼 자식 칼럼을 세는 것입니다. COUNT(*)로 세면 짝이 없는 회원도 1로 세어져 0이 아니라 1이 나옵니다. 채점은 사라지는 행의 지적 2점, 아우터 조인으로의 수정 1점, COUNT 대상 칼럼까지 짚으면 1점입니다.
SQL 전문가(SQLP) 시험 노트 전체 보기