March 09, 2021
관계형 데이터베이스 대표적 기초서적인 ‘관계형 데이터베이스 실전 입문’을 읽고 각 장마다 정리한 글입니다.
관계형 데이터베이스에 질의를 하기 위한 언어. 그러나 SQL 구문이나 문법만 봐서는 관계형 모델이 어떤 것인지는 알 수 없다.
관계형 모델은 실제 세계의 데이터를 관계 라는 개념을 사용해 표현한 데이터 모델이다.
관계형 모델이 나타내는 데이터 모델은 설계의 의미가 아니고 데이터를 어떻게 표현 할까 라는 개념의 의미다.
관계형 모델을 이해하는데 가장 중요한 개념이 관계(릴레이션) 이다.
SQL에 있어 릴레이션에 해당하는 것은 테이블이다. 관계형 모델에서 릴레이션의 정의는 다음과 같다.
릴레이션은 제목(Heading)과 본체(Body)로 구성돼 있다.
제목은 속성(Attribute)이 n개 모인 집합이며, 이 속성은 이름과 데이터 형으로 되어 있다. 본체는 속성값의 집합인 행 또는 튜플의 집합이다.
튜플에 포함된 속성값은 이름과 데이터 형이 제목에서 지정한 것과 서로 일치하지 않으면 안된다. 제목에서 정의하지 않은 속성이 튜플에 존재하거나, 반대로 제목에는 포함된 속성이 튜플에는 존재하지 않는 경우는 규칙 위반이다.
→ 릴레이션은 튜플의 집합이며, 튜플은 모두 같은 n개의 속성값의 집합으로, 데이터 구성이 서로 같다.
튜플과 속성을 SQL에서는 각각 로우, 컬럼이라고 한다.
관계형 모델 | SQL |
---|---|
릴레이션 | 테이블 |
튜플 | 행 |
속성(Attribute) | 컬럼 |
집합은 물건의 모임을 표현하는 개념으로 집합에 포함된 각 물건을 요소나 원소(Element)라고 한다. 요소에는 특별한 제약이 없으며 범용적인 구조로써 집합을 사용할 수 있다.
릴레이션도 집합의 한 종류이므로 집합이 가진 특성은 릴레이션에도 응용할 수 있다.
집합의 요소는 충족해야 할 조건이 두 가지 정도 있다.
릴레이션에 NULL을 포함 할 수 없다. NULL은 값이 아니고 요소가 무엇인지 모르는, 즉 알 수 없는 값임을 나타내는 표식이다.
관계형 모델을 올바르게 구현하려면 NULL을 배제해야 한다.
관계형 모델이 다루는 것은 유한집합뿐이다.
→ 무한집합은 고려할 필요가 없다.
데이터를 릴레이션이라고 표현한다면 그에 대한 연산은 쿼리(질의)이다. 관계형 모델은 릴레이션 단위로 다양한 연산을 사용해 질의를 수행하는 데이터 모델이다. 릴레이션을 사용한 연산을 수행하므로 관계형 모델이라고 부른다.
릴레이션은 튜플의 집합이다. 릴레이션은 본질적으로는 집합이며 그에 대한 연산도 집합론을 바탕으로 하고 있다.
그러나 릴레이션 내의 튜플이 모드 같은 구조, 같은 이름 즉 같은 데이터 형을 가지므로 일반적인 집합에는 없는 관계형 모델 특유의 연산이 많이 있다.
제한은 어떤 릴레이션들 중에 특정 조건에 맞는 튜플을 포함한 릴레이션을 반환한다. 제한을 실행한 결과는 원래 릴레이션의 부분집합이라고 할 수 있다. 조건을 지정하는 방법은 특별히 제한을 두지 않는다.
→ 제한을 실행한 결과가 공지합이 되거나 원래의 릴레이션과 같은 결과가 나올 수도 있다.
프로젝션은 어떤 릴레이션에서 특정 속성만 포함하는 릴레이션을 반환한다.
속성이 적어지면 튜플의 중복이 발생할 수 있다. → 집합은 중복되는 요소를 포함할 수 없으므로 중복이 발생한 경우에는 같은 튜플로 간주한다.
확장은 프로젝션과는 반대로 속성을 늘리는 동작이다. 대부분 새로운 속성값은 기존의 속성값을 이용해 계산한다.
속성명 변경은 단순히 속성의 이름을 변경하는 동작이다. 실제로는 주로 확장한 속성에 명칭을 부여할 때 많이 사용한다.
합집합은 두 개의 릴레이션에 포함된 모든 튜플로 구성된 릴레이션(합집합)을 반환한다. 두 개의 릴레이션에 공통된 속성값이 포함됐다면 합집합은 중복 값이 제거된 상태가 된다.
교집합은 두 개의 릴레이션에 모두 포함된(공통부분) 릴레이션을 반환한다.
차집합은 두 개의 릴레이션 중에 한쪽의 릴레이션에만 포함되어 있는 튜플로 구성된 릴레이션을 반환한다. 차집합은 어느 쪽의 릴레이션을 기준으로 정하는 지에 따라서 결과가 달라진다.
곱집합은 두 개의 릴레이션에 있는 튜플을 각각 조합한 릴레이션을 반환한다. 이때 릴레이션의 제목은 두 개의 릴레이션의 제목이 가진 속성을 전부 포함한다.
결합은 공통된 속성을 가진 두 개의 릴레이션에서 공통된 속성값이 같은 튜플끼리 조합한 릴레이션을 반환한다.
결과적으로 반환되는 튜플은 두 개의 릴레이션에서 공통된 속성에 관해 같은 값이 존재하는 것뿐이다. 즉 일치하는 값이 존재하지 않는 튜플은 결과에서 제외된다. → 내부조인(INNER JOIN)
사실은 관계형 모델에 존재하는 것은 내부조인뿐이다. 외부조인은 결과에 NULL이 포함될 가능성이 있으므로 릴레이션의 연산으로는 부적절하다.
교집합과 곱집합은 결합의 특수한 예다. 교집합은 두 개의 릴레이션에 포함되는 속성이 전부 공통인 경우이고 반대로 곱집합은 공통의 속성이 존재하지 않는 경우다.
관계형 모델에서 중요한 것은 릴레이션을 사용한 연산 결과가 릴레이션이 되는 것이다.
연산의 입력과 출력이 같은 데이터 구조를 가진 성질을 클로저(폐쇄) 라고 한다.
릴레이션의 연산만을 이용해 복잡한 연산을 표현할 수 있다는 점이 관계형 모델의 진면목이다.
데이터 형식이란 각 속성이 어떤 값을 가질 것인지를 말한다.
SQL의 데이터 형식으로는 INT, CHAR, VARCHAR 와 같은 것이 있다. 관계형 모델에선 어떻게 표현할까?
관계형 모델은 문자 그대로 모델 이므로 어떻게 사용해야 한다 는 모델을 사용하는 응용프로그램이 정해야 한다.
데이터 형식을 이해하려면 먼저 변수와 값에 대해 이해해야 한다.
컴퓨터가 표현할 수 있는 데이터는 변경할 수 있는 한계가 있다.
→ 데이터 형식은 그 변수에 대입할 수 있는 값의 유한집합이다.
관계형 모델에서 데이터 형식은 도메인 이라 한다.
값은 그 집합의 요소 하나하나이고 변수는 어떤 시점에 그 집합에서 요소를 한 개 선택한 것으로 해석한다. 집합의 요소(값)에는 변화가 없지만 어떤 요소를 선택할 것인가(변수)는 변한다.
→ 그 집합 전체를 도메인이라 한다.
SQL과 관계형 모델은 차이
SELECT 칼럼의 목록
FROM 테이블의 목록
WHERE 검색 조건
칼럼의 목록은 프로젝션, 테이블의 목록은 곱집합, 검색조건은 제한이다.
SELECT는 세 개의 릴레이션 연산을 동시에 수행하는 작업이다.
SELECT에서는 세가지의 릴레이션 연산이 다음과 같은 순서로 평가된다.
SELECT의 뒤에는 컬럼을 직접 지정하는 것 외에 그 컬럼의 연산 결과도 지정할 수 있다.
관계형 모델에서는 새로운 속성(SQL에서는 컬럼)을 추가하는 작업을 확장이라고 한다. 평가는 프로젝션 직전에 수행된다.
사실 관계형 모델에는 갱신이라는 개념이 존재하지 않는다.
릴레이션을 갱신하는 것은 불가능하다. → 릴레이션은 값이기 때문.
INSERT는 행을 추가하지만, 행을 추가해 테이블의 값(릴레이션)이 바뀌는 것처럼 보인다.
테이블이 값과 변수라는 양쪽의 역할을 하기 때문이다. 관계형 모델에서 릴레이션을 저장하는 변수는 Relvar(Relation Variable, 관계 변수) 라고 한다.
→ SQL에서 테이블의 갱신 처리는 Relvar의 역할로 테이블에 할당된 릴레이션의 값을 변경하는 것!
INSERT는 Relvar의 값(릴레이션)을 해당 릴레이션에 새롭게 INSERT 할 튜플을 추가하고 릴레이션과 바꾸는 작업에 해당한다. 관계형 모델에서 릴레이션의 연산은 입력도 출력도 릴레이션이다. → 합집합
INSERT INTO t (c1, c2, c3) VALUES (1, 2, 3);
DELETE는 차집합이라고 할 수 있다.
DELETE FROM t WHERE c1 = 100;
관계형 모델로 표현하면 전체 릴레이션(Relvar에 대입되는 값)에서 WHERE 절의 조건인 c1 = 100에 해당하는 튜플의 집합(전체의 릴레이션의 부분집합)이 되고 릴레이션의 차집합을 Relvar에 대입하는 것과 같다.
DELETE는 Relvar을 WHERE 절의 조건에 만족하지 않은 튜플로 이뤄진 릴레이션으로 바꾸는 것과 같다.
UPDATE t SET c1 = 1 WHERE c2 = 123;
UPDATE 문은 전체 릴레이션에 포함된 튜플 중에서 WHERE 절의 조건에 맞는 튜플 값을 SET 절의 내용에 맞게 갱신하는 작업이다. → 값 자체는 갱신할 수 없으므로 튜플의 값을 바꾼다는 것은 관계형 모델에서는 틀렸다.
SQL에서도 UPDATE는 DELETE, INSERT의 조합으로 표현한다.
SQL을 효과적으로 사용하기 위한 요령은 무엇보다도 관계형 모델에 맞게 사용하는 것.
SQL은 테이블에 같은 행이 있더라도 괜찮다. 기본키와 같은 유일성 제약이 있다면 테이블에 중복되는 행이 존재하지 않지만, 아무런 제약이 없다면 중복된 행이 있더라도 오류가 아니다.
→ 테이블은 원래 집합이 아니다.
테이블은 다중집합이라고 할 수 있다.
SQL을 관계형 모델에 맞게 사용하려면 테이블을 집합처럼 사용해야 한다. 적어도 어딘가 유일성 제약이 있어야 한다.
집합은 요소 사이의 순서가 없다.
SQL에는 순서가 있다. 컬럼은 정의된 순서대로 나열되고 행을 정렬할 수도 있다. 쿼리를 실행한 결과도 지정한 순서로 나열된다.
관계형 모델에 따라 SQL을 사용하려면 행이나 컬럼의 위치를 고려한 쿼리를 작성해서는 안된다.
→ ROWNUM, ORDER BY 1 등등 피할 것.
릴레이션은 값이므로 갱신할 수 없다. 값을 갱신할 수 있는 것은 변수뿐이다.
테이블이 값과 변수의 기능을 모두 겸한다는 점이다.
트랜잭션은 SQL 사양의 일부이지만, 관계형 모델과는 다른 독립적인 개념으로 관계형 모델에 포함되지 않는다.
두 가지는 상호 보완적인 관계이며 RDB에서 두개의 축이다.
트랜잭션은 여러 개의 병렬로 실행된 갱신을 모순 없이 수행하기 위한 이론이지만, 릴레이션은 갱신이 없으므로 트랜잭션의 ACID 특성은 아무런 관계가 없다.
트랜잭션은 값과 변수 두 가지 성질을 겸하는 테이블이라는 개념이 있고 SQL이기 때문에 의미가 있는 개념이다.
관계형 모델에는 프로시저가 없다. 커서를 루프로 처리하는 작업은 관계형 모델에서는 없다.
→ 테이블을 루프로 처리하는 것은 집합 연산을 정면으로 부정하는 행위다.
집합에는 NULL이라는 개념이 없다. 단지 요소가 포함돼 있을 뿐.
SQL을 올바르게 관계형 모델에 맞게 사용하는데 있어서 NULL 처리는 매우 중요하다.