식별자Identifiers의 개념
식별자는 엔터티 내에서 인스턴스들을 구분하는 구분자로, 엔터티를 대표하는 속성이다. 따라서 하나의 엔터티에는 반드시 하나의 유일한 식별자가 존재한다. 보통 식별자와 키Key를 동일하게 사용하는데, 논리 데이터 모델링 단계에서는 업무적으로 구분이 되는 '식별자'로, 물리 데이터 모델링 단계에서는 DB 테이블 접근을 위핸 매개체로서 '키'를 사용한다.
식별자의 특징
- 유일성: 주식별자에 의해 엔터티 내 모든 인스턴스들이 유일하게 구분된다.
- 최소성: 주식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수이다.
- 불변성: 지정된 주식별자의 값은 자주 변하지 않는다.
- 존재성: 주식별자가 지정되면 반드시 값이 들어와야 한다. Null 값도 안된다.
대체식별자의 특징은 주식별자의 특징과 일치하지만, 외부식별자의 경우 주식별자 특징과 일치하지 않으며 참조무결성 제약조건(Referential Integrity)에 따른 특징을 가지고 있다.
주식별자PK와 키의 종류
-주식별자는 유일성과 최소성을 만족하는 키로, 엔터티를 대표할 수 있어야 한다
-자주 변경되지 않아야 하며 엔터티의 인스턴스를 유일하게 식별한다
데이터베이스 키 | 설명 |
기본키PK | 후보키 중 엔터티를 대표할 수 있는 키 |
후보키Candidate Key | 유일성과 최소성을 만족하는 키 |
슈퍼키Super Key | 유일성은 만족하지만 최소성(Not Null)은 만족하지 않는 키 |
대체키Alternate Key | 여러 개의 후보키 중 기본키를 선정하고 남은 키 |
식별자 분류
1. 대표성 여부에 따른 식별자 종류
종류 | 설명 |
주식별자PK | 유일성, 최소성, 대표성을 만족한다. 다른 엔터티와 참조관계로 연결될 수 있다. |
보조식별자 | 유일성, 최소성은 만족하지만 대표성을 만족하지 못해 참조관계를 연결하지 못한다. |
2. 스스로 생성 여부에 따른 식별자 종류
종류 | 설명 |
내부식별자 | 엔터티 내부에서 스스로 만들어지는 식별자 |
외부식별자 | 다른 엔터티와의 관계로 인해 만들어지는 식별자 |
3. 속성의 수에 따른 식별자 종류
종류 | 설명 |
단일식별자 | 하나의 속성으로 구성되는 식별자 |
복합식별자 | 두 개이상의 속성으로 구성되는 식별자 |
4. 대체 여부에 따른 식별자 종류
종류 | 설명 |
본질식별자 | 비즈니스 프로세스에서(업무에 의해) 만들어지는 식별자 |
인조식별자 | 최대한 범용적인 값을 사용하고 유일한 값을 만들기 위해 인위적으로 만들어지는 식별자. |
'사번'은 인조식별자가 아니라 본질식별자임 (?)
식별자 표기법
주식별자 도출기준
1. 해당 업무에서 자주 이용되는 속성을 주식별자로 지정한다.
2. 명칭, 내역 등과 같이 이름으로 기술되는 것들은 가능하면 주식별자로 지정하지 않는다. 특히 '이름'은 최악(동명이인)
3. 복합으로 주식별자를 구성할 경우 너무 많은 속성이 포함되지 않도록 새로운 인조식별자를 생성한다.
이러한 모델의 경우 실제 테이블에 PK는 7개가 생성될 것이고 만약 특정 신청인의 계약금 하나만 가져온다고 하더라도 다음과 같이 복잡한 SQL문장을 구사해야 한다.
SELECT 계약금
FROM 접수
WHERE 접수.접수일자 = '2010.07.15'
AND 접수.관할부서 = '1001'
AND 접수.입력자사번 = 'AB45588'
AND 접수.접수방법코드 = 'E'
AND 접수.신청인구분코드 = '01'
AND 접수.신청인주민번호 = '7007171234567'
AND 접수.신청횟수 = '1'
이렇게 된 SQL문장을 접수번호라고 하는 인조식별자로 대체했다고 하면 특정신청인의 계약금 조회는 다음과 같이 간단하게 할 수 있다.
SELECT 계약금
FROM 접수
WHERE 접수.접수일자 = '100120100715001'
식별자관계와 비식별자관계
엔터티 사이 관계유형은 업무특징, 자식엔터티의 주식별자구성, SQL 전략에 의해 결정된다.
1. 식별자관계Identifying Relationship
-부모 식별자를 자식엔터티의 주식별자로 이용하는 경우에 Null 값이 오면 안돼서 반드시 부모엔터티가 생성되어야 자기 자신의 엔터티(자식엔터티)가 생성되는 경우다.
-부모한테 받은 속성을 자식엔터티가 모두 사용하고 그것만을 주식별자로 사용한다면 부모엔터티와 자식엔터티의 관계는 1:1의 관계가 된다. 부모로부터 받은 속성을 포함하여 다른 부모에게 받은 속성을 포함하거나 스스로 가지고 있는 속성과 함께 주식별자로 지정하는 경우는 1:M 관계가 된다.
-이 때 식별자를 공유한 부모엔터티를 '강한 개체Strong Entity', 공유받은 자식엔터티를 '약한 개체Weak Entity'라고 한다.
다음의 경우엔 식별자 관계로 설정하는 것이 좋다.
- 반드시 부모엔터티에 종속되는 경우
- 자식 주식별자의 구성에 부모의 주식별자가 포함되어야 하는 경우
- 여러 개의 엔터티가 하나의 엔터티상속받은 주식별자 속성을 타 엔터티에 이전할 필요가 있는 경우
2. 비식별자관계Non-Identifying Relationship
부모엔터티로부터 속성을 받았지만 자식엔터티의 주식별자로 사용하지 않고 일반적인 속성으로만 사용하는 경우를 비식별자 관계라고 한다. 강한 개체의 기본키를 다른 엔터티의 기본키가 아니 일반 칼럼의 관계로 가지는 것.
다음의 경우엔 비식별자 관계로 설정하는 것이 좋다.
- 관계의 강약을 분석해 상호 연관성이 약한 경우
- SQL문의 복잡성이 증가되는 것을 피하고 싶은 경우(모든 관계가 식별관계로 연결되면 Where절에서 비교하는 항목이 증가되어 조인에 참여하는 테이블에 따라 SQL문이 길어진다)
- 부모 엔터티에 참조값이 없어도 자식 엔터티의 인스턴스가 생성될 수 있는 경우
- 엔터티별로 데이터의 생명주기Life Cycle이 다를 경우 ex. 부모엔터티가 자식을 남겨두고 '먼저' 소멸될 수 있는 경우
- 여러 개의 엔터티가 하나의 엔터티로 통합되었는데 각각의 엔터티가 별도의 관계를 가질 경우
위 그림은 접수엔터티가 인터넷접수, 내방접수, 전화접수가 하나로 통합되어 표현되어 있는 경우로, 통합된 엔터티의 각각의 엔터티가 별도의 관계를 가지고 있고 각각의 관계로부터 받은 주식별자를 접수엔터티의 주식별자로 사용할 수 없는 모습을 보여준다.
- 자식엔터티의 주식별자로 사용해도 되지만 자식엔터티에서 별도의 주식별자를 생성하는 것이 더 유리하다고 판단될 경우, 자식테이블에서 독립적인 PK 구조를 가지기 원할 경우
위 그림은 계약이 반드시 사원에 의해 이루어져 사원번호와 계약번호로 주식별자를 구성할 수 있지만 계약번호 단독으로도 계약 엔터티의 주식별자를 구성할 수 있어서, 하나만 가지고 있는 것이 더 효율적이라고 판단할 수 있다. 계약번호만 주식별자로 하고 계약사원번호는 일반속성 FK로서 사용하게 된 경우이다.
식별자 관계로만 설정할 경우의 문제점
단지 식별자관계, 비식별자관계에 대한 설정을 고려하지 않은 것이 개발의 복잡성을 증가시키는 요인이 될까?
위의 데이터 모델은, 원시 엔터티이었던 PLANT의 경우 PK속성이 1개였지만 EQPEVTSTSHST 엔터티의 경우 모두 식별자관계 연결로 인해 부모로부터 PK속성의 개수가 5개나 설정될 수 밖에 없게 된 사례이다.
즉, PLANT 엔터티에는 PK속성의 수가 1개이고 관계가 1:M이므로 자식엔터티의 PK 수는 PLANT 엔터티의 (PK속성의 수 + 1)이 성립된다. 물론 1개 이상의 속성이 추가되어야 1:M 관계를 만족할 수 있다. 이와 같은 원리에 의해 1:M 관계의 식별자관계의 PK속성의 수는 다음과 같다.
원 부모엔터티 : 1개
2대 부모엔터티 : 2개 이상 = 원부모 1개 + 추가 1개 이상
3대 부모엔터티 : 3개 이상 = 원부모 1개 + 2대 1개 + 3대 1개 + 추가 1개 이상
4대 부모엔터티 : 4개 이상 = 원부모 1개 + 2대 1개 + 3대 1개 + 4대 1개 + 추가 1개 이상 ....
이와 같은 규칙에 의해 지속적으로 식별자 관계를 연결한 데이터 모델의 PK속성의 수는 데이터 모델의 흐름이 길어질수록 증가할 수 밖에 없다.
위 그림의 예시 모델에서 EQPEVTSTSHST에 설정된 PK속성을 이용하여 해당 이력의 수리 ITEM과 작업자에 대한 엔터티가 별도로 발생이 가능한 데이터 모델을 만든다면 아래와 같이 PK속성 수가 많아질 수 밖에 없다.
예시 모델의 맨 하위에 있는 EQPEVTSTSHST에서 다시 새로운 엔터티 EQP_ITEM, EQP_WORKER와 관계를 맺고 있을 때 이 세 개의 엔터티에서 정보를 가져오는 SQL구문을 작성해 보자.
SELECT A.EVENT_ID, A.TRANS_TIME, A.HST_DEL_FLAG, A.STATUS_PROMPT, A.STATUS_OLD, A.STATUS_NEW
FROM EQPEVTSTSHST A, EQP_ITEM B, EQP_WORKER C
WHERE A.PLANT = B.PLANT
AND A.EQUIPMENT_ID = B.EQUIPMENT_ID
AND A.STATUS_SEQ = B.STATUS_SEQ
AND A.EVENT_ID = B.EVENT_ID
AND A.TRANS_TIME = B.TRANS_TIME
AND B.ITEM_CD = 'A001'
AND A.PLANT = C.PLANT
AND A.EQUIPMENT_ID = C.EQUIPMENT_ID
AND A.STATUS_SEQ = C.STATUS_SEQ
AND A.EVENT_ID = C.EVENT_ID
AND A.TRANS_TIME = C.TRANS_TIME
AND C.WORKER_SID = 'A012008001'
고작 3개의 엔터티를 조인했을 뿐인데 SQL구문의 WHERE절이 매우 길어졌다. 위와 같이 조인에 참여하는 주식별자속성의 수가 많을 경우 정확하게 조인관계를 설정하지 않고 즉, 누락하여 개발하는 경우가 생길 수도 있다. 정리하면 식별자 관계만으로 연결된 데이터 모델은 주식별자 속성이 지속적으로 증가할 수 밖에 없는 구조로서 개발자 복잡성과 오류가능성을 유발시킬 수 있는 요인이 될 수 있다는 것이다.
비식별자 관계로만 설정할 경우의 문제점
일반적으로 각각의 엔터티에는 중요한 기준속성이 있는데 이러한 기준속성은 부모엔터티의 PK속성으로부터 상속되어 자식엔터티에 존재하는 경우가 많다. 이러한 속성의 예로 ‘주민등록번호’, ‘사원번호’, ‘주문번호’, ‘목록번호’ 등이 있다. 이런 속성은 부모엔터티를 조회할 때도 당연히 쓰이지만 자식엔터티의 데이터를 조회할 때도 해당 조건이 조회의 조건으로 걸리는 경우가 다수이다. 그런데 데이터 모델링을 전개할 때 각 엔터티 간의 관계를 비식별자 관계로 설정하면 이런 유형의 속성이 자식엔터티로 상속이 되지 않아 자식엔터티에서 데이터를 처리할 때 쓸데없이 부모엔터티까지 찾아가야 하는 경우가 발생된다.
위의 예에서는 REP001T, REP005T, REP007T 간의 관계가 비식별자 관계로 연결되면서 점검번호, 분야번호 속성이 관계를 타고 자식엔터티로 내려가는 것을 차단하였다. 이러한 모델에서는 만약 맨 하위에 있는 REP007T 엔터티에서 어떤 점검에 대한 정보를 보려고 하면 불필요한 조인이 다량으로 유발되면서 SQL구문도 길어지고 성능이 저하되는 현상이 발생이 된다.
위 표의 조회 패턴을 보면 고작 조회 조건은 점검번호='301'로, 간단하면서도 이 업무에서는 가장 근간이 되는 조회 패턴 정보로 여겨진다. 하지만 단순하게 걸리는 이 하나의 조회 조건도 왼쪽과 같이 비식별자 관계로만 데이터 모델링을 전개하다 보면 SQL구문에 많은 조인이 걸리게 되고 그에 따라 복잡성이 증가하고 성능이 저하되게 되는 것이다. 반면 오른쪽과 같이 식별자관계를 통해 연결하다보면, 부모의 모든 주식별자 속성을 상속받아 맨 하위에 있는 자식엔터티에서 바로 조회의 조건을 이용하여 원하는 정보를 가져올 수 있다. 당연히 성능과 개발의 용이성 측면에서는 식별자관계가 우위에 있음을 보여준다.
따라서 이 두 가지 경우에 대해서 일정한 규칙을 가지고 데이터 모델링을 하는 기술이 필요하며, 다음에 제시된 고려사항을 데이터 모델링에 반영한다면 효과적인 데이터 모델을 만들어 내는데 유용하게 활용할 수 있다.
'SQLD > 데이터 모델링의 이해' 카테고리의 다른 글
2-2 정규화와 성능 (0) | 2020.02.16 |
---|---|
2-1 성능 데이터모델링의 개요 (0) | 2020.02.16 |
1-4 관계 (0) | 2020.02.13 |
1-3 속성 (0) | 2020.02.13 |
1-2 엔터티 (0) | 2020.02.13 |