출제기준 세세항목: 관계 데이터 모델 · 관계데이터언어(관계대수, 관계해석) · 시스템카탈로그와 뷰
관계 데이터 모델은 1970년 코드(E. F. Codd)가 제안한 모델로, 데이터를 행과 열로 이뤄진 표로 표현합니다. 이 표를 릴레이션(Relation)이라고 부릅니다. 개체 사이의 관계도 따로 연결 구조를 두지 않고 표 안의 값(외래키)으로 나타낸다는 점이, 포인터로 잇는 계층형·네트워크형 모델과 다릅니다.
릴레이션의 용어를 정확히 알아 둡시다. 표의 한 행을 튜플(Tuple), 한 열을 속성(Attribute)이라고 합니다. 한 속성이 가질 수 있는 값 전체의 집합은 도메인(Domain)입니다. '학년' 속성의 도메인은 {1, 2, 3, 4}처럼 정해집니다. 속성의 개수를 차수(Degree), 튜플의 개수를 카디널리티(Cardinality, 기수)라고 합니다. 학번·이름·학과 세 열에 학생 50명이 들어 있다면 차수는 3, 카디널리티는 50입니다.
릴레이션의 이름과 속성 목록, 즉 틀을 릴레이션 스키마라 하고, 어느 순간 실제로 들어 있는 튜플들의 모임을 릴레이션 인스턴스라고 합니다. 스키마는 잘 바뀌지 않지만 인스턴스는 데이터가 들어오고 나갈 때마다 바뀝니다. 그래서 차수는 거의 그대로이고 카디널리티는 수시로 바뀝니다.
릴레이션에는 지켜야 할 성질이 있습니다. 똑같은 튜플이 두 번 있을 수 없고, 튜플 사이에는 순서가 없으며, 속성 사이의 순서도 의미가 없습니다. 또 각 속성 값은 더 쪼갤 수 없는 하나의 값(원자값)이어야 합니다. '취미' 칸에 '독서, 등산'처럼 여러 값을 함께 넣는 것은 이 성질을 어긴 것입니다.
키(Key)는 튜플을 서로 구별하거나 다른 릴레이션과 이을 때 기준이 되는 속성 또는 속성의 묶음입니다. 키를 이해하려면 두 성질을 먼저 알아야 합니다. 유일성은 그 키 값으로 모든 튜플을 하나씩 가려낼 수 있다는 성질이고, 최소성은 키를 이루는 속성 중 하나라도 빼면 유일성이 깨진다는 성질, 즉 꼭 필요한 속성만 들어 있다는 성질입니다.
슈퍼키(Super Key)는 유일성만 만족하는 키입니다. [학생]에서 학번이 유일하다면 (학번, 이름)도 유일하므로 슈퍼키입니다. 후보키(Candidate Key)는 유일성과 최소성을 모두 만족하는 키로, 학번처럼 그것만으로 꼭 맞게 구별되는 것입니다. 후보키 가운데 대표로 고른 것이 기본키(Primary Key)이고, 기본키로 뽑히지 않고 남은 후보키가 대체키(Alternate Key)입니다.
외래키(Foreign Key)는 다른 릴레이션의 기본키를 참조하는 속성입니다. [수강]의 학번이 [학생]의 학번을 가리키면 [수강].학번이 외래키입니다. 외래키 덕분에 표가 따로 떨어져 있어도 서로 이을 수 있습니다. 외래키는 같은 릴레이션의 기본키를 참조할 수도 있는데, [직원]의 상사사번이 같은 표의 사번을 가리키는 경우가 그렇습니다.
무결성은 데이터베이스에 들어 있는 값이 정확하고 서로 모순이 없는 상태를 말하고, 이를 지키려고 정해 두는 규칙이 무결성 제약 조건입니다. 가장 중요한 두 가지는 개체 무결성과 참조 무결성입니다.
개체 무결성은 기본키를 이루는 속성이 NULL일 수 없고 중복될 수도 없다는 규칙입니다. 기본키는 튜플을 가려내는 이름표인데, 이름표가 비어 있거나 겹치면 구별할 수 없기 때문입니다. 참조 무결성은 외래키 값이 참조하는 릴레이션의 기본키 값 중 하나이거나 NULL이어야 한다는 규칙입니다. [주문]의 고객번호에 [고객] 표에 없는 번호가 적혀 있으면, 존재하지 않는 고객의 주문이 생겨 버립니다.
이 밖에 속성 값이 정해진 도메인 안에 있어야 한다는 도메인 무결성(학년에 7이나 '많음'이 들어가면 안 됨), 업무 규칙에 맞아야 한다는 사용자 정의 무결성, 특정 속성에 NULL을 허용하지 않는 NULL 무결성, 특정 속성의 값이 서로 달라야 한다는 고유 무결성, 릴레이션에 키가 적어도 하나 있어야 한다는 키 무결성이 있습니다. SQL에서는 PRIMARY KEY, FOREIGN KEY, CHECK, NOT NULL, UNIQUE 같은 제약 조건으로 지정합니다.
참조되는 쪽의 행을 지우거나 기본키를 바꿀 때 참조하는 쪽을 어떻게 할지도 정해 둘 수 있습니다. 함께 지우거나 바꾸는 CASCADE, 참조하던 값을 NULL로 바꾸는 SET NULL, 참조하는 행이 있으면 변경을 막는 RESTRICT(또는 NO ACTION)가 대표적입니다. 고객을 지울 때 그 고객의 주문까지 함께 지울지, 아예 지우지 못하게 막을지를 정하는 셈입니다.
관계데이터언어는 릴레이션에서 원하는 데이터를 꺼내는 방법을 이론적으로 정리한 언어로, 관계대수와 관계해석이 있습니다. 관계대수는 릴레이션을 입력으로 받아 연산하고 다시 릴레이션을 결과로 내놓는 연산자들의 모음입니다. 어떤 연산을 어떤 순서로 적용할지를 적기 때문에 절차적 언어라고 합니다.
관계대수에만 있는 순수 관계 연산자는 네 가지입니다. 셀렉트(Select, σ)는 조건에 맞는 튜플(행)만 골라 표를 가로로 자르고, 프로젝트(Project, π)는 원하는 속성(열)만 골라 세로로 자릅니다. 조인(Join, ⋈)은 공통 속성을 기준으로 두 릴레이션을 하나로 잇고, 디비전(Division, ÷)은 한 릴레이션에서 다른 릴레이션의 모든 값과 짝을 이루는 튜플을 찾습니다. '필수 과목을 모두 들은 학생'을 구하는 것이 디비전의 전형적인 쓰임입니다. 셀렉트(σ)는 이름과 달리 SQL의 WHERE 절에, 프로젝트(π)가 SQL의 SELECT 절에 가깝다는 점에 주의하세요.
일반 집합 연산자도 씁니다. 합집합(∪), 교집합(∩), 차집합(−)은 두 릴레이션의 튜플을 집합처럼 합치고, 겹치는 것만 고르고, 빼는 연산이라, 두 릴레이션의 차수가 같고 대응하는 속성의 도메인이 같을 때(합병 가능할 때)만 쓸 수 있습니다. 교차곱(카티션 곱, ×)은 두 릴레이션의 튜플을 모두 짝지으므로, 결과의 차수는 두 차수의 합, 카디널리티는 두 카디널리티의 곱입니다. 차수 3·카디널리티 4인 릴레이션과 차수 2·카디널리티 5인 릴레이션을 교차곱하면 차수 5, 카디널리티 20이 됩니다.
관계해석은 코드가 수학의 술어 해석(Predicate Calculus)을 바탕으로 제안한 언어입니다. 관계대수가 '이 표에서 이 조건으로 고르고, 저 표와 이어라'처럼 절차를 적는다면, 관계해석은 '이런 조건을 만족하는 튜플들'처럼 원하는 결과의 모양만 적습니다. 그래서 비절차적 언어라고 합니다.
관계해석은 무엇을 변수로 다루느냐에 따라 둘로 나뉩니다. 튜플 관계해석은 튜플 하나를 변수로 놓고 조건을 적고, 도메인 관계해석은 속성 값, 즉 도메인의 원소를 변수로 놓고 조건을 적습니다. 조건에는 '적어도 하나 있다'는 존재 정량자(∃)와 '모든 것에 대해'라는 전칭 정량자(∀) 같은 기호가 쓰입니다.
관계대수와 관계해석은 표현할 수 있는 질의의 범위가 같다고 알려져 있습니다. 실제 SQL은 두 언어의 생각을 모두 이어받았습니다. 사용자는 원하는 것만 적고 처리 절차(실행 계획)는 DBMS가 정한다는 점은 관계해석에 가깝고, DBMS가 그 요청을 내부에서 연산의 조합으로 바꿔 실행한다는 점은 관계대수에 가깝습니다.
시스템 카탈로그(System Catalog)는 데이터베이스 자신에 관한 정보, 즉 어떤 테이블이 있고 각 테이블에 어떤 열과 제약 조건, 인덱스가 있는지, 어떤 뷰와 사용자, 권한이 있는지를 담은 곳입니다. 데이터에 관한 데이터라는 뜻에서 이런 정보를 메타데이터(Metadata)라 하고, 카탈로그를 데이터 사전(Data Dictionary)이라고도 부릅니다.
카탈로그도 테이블 모양으로 저장되어 있어 사용자가 SELECT로 조회할 수 있습니다. 하지만 내용을 만들고 고치는 것은 DBMS가 스스로 합니다. 사용자가 CREATE TABLE을 실행하면 DBMS가 카탈로그에 그 테이블의 정보를 자동으로 기록하는 식이고, 사용자가 INSERT, UPDATE, DELETE로 카탈로그를 직접 고칠 수는 없습니다. DBMS는 질의를 처리할 때 카탈로그를 보고 테이블이 있는지, 권한이 있는지를 확인합니다.
뷰(View)는 하나 이상의 기본 테이블에서 유도된 가상 테이블입니다. 데이터를 따로 저장하지 않고 조회문(정의)만 저장해 두었다가, 뷰를 조회할 때마다 그 정의를 실행해 결과를 보여 줍니다. CREATE VIEW로 만들고 DROP VIEW로 지웁니다. 복잡한 조회를 이름 하나로 간단히 쓸 수 있고, 보여 줄 열과 행만 골라 주어 보안에 도움이 되며, 기본 테이블 구조가 조금 바뀌어도 뷰를 쓰는 프로그램은 그대로 쓸 수 있다는 것(논리적 데이터 독립성)이 장점입니다.
한계도 있습니다. 뷰는 자기만의 인덱스를 가질 수 없고, 조인이나 그룹 함수, DISTINCT가 들어간 뷰는 INSERT·UPDATE·DELETE에 제약이 많습니다. 표준 SQL에는 뷰의 정의를 고치는 명령이 따로 없어서, 정의를 바꾸려면 지우고 다시 만들거나 DBMS가 제공하는 CREATE OR REPLACE VIEW를 씁니다. 기본 테이블을 지우면 그 위에 만든 뷰도 쓸 수 없게 됩니다. 뷰를 통해 데이터를 바꿀 때 뷰의 조건을 벗어나는 변경을 막으려면 정의 끝에 WITH CHECK OPTION을 붙입니다.
트랜잭션(Transaction)은 데이터베이스에서 한 번에 처리돼야 하는 작업의 논리적 단위입니다. 계좌 이체는 'A 계좌에서 빼기'와 'B 계좌에 더하기' 두 번의 변경으로 이뤄지는데, 둘 중 하나만 되면 돈이 사라지거나 생겨나므로 하나의 트랜잭션으로 묶어야 합니다.
트랜잭션은 네 가지 성질을 지켜야 합니다. 원자성(Atomicity)은 모두 반영되거나 하나도 반영되지 않아야 한다는 것(All or Nothing)입니다. 일관성(Consistency)은 트랜잭션이 끝난 뒤에도 데이터베이스가 무결성 제약을 만족하는 올바른 상태여야 한다는 것입니다. 격리성(Isolation, 독립성)은 동시에 실행되는 트랜잭션들이 서로의 중간 결과를 보거나 간섭하지 않아야 한다는 것이고, 영속성(Durability, 지속성)은 한 번 COMMIT된 결과는 장애가 나도 사라지지 않아야 한다는 것입니다. 네 성질의 앞 글자를 따 ACID라고 부릅니다.
각 성질은 DBMS의 서로 다른 기능이 맡습니다. 원자성은 COMMIT·ROLLBACK과 장애 때 되돌리는 회복 기능이, 격리성은 로킹(Locking) 같은 병행 제어가, 영속성은 변경을 로그로 남겨 두었다가 장애 뒤 다시 반영하는 회복 기법이 지켜 줍니다. 트랜잭션은 실행 중인 활동(Active), 마지막 연산까지 실행했지만 아직 확정 전인 부분 완료(Partially Committed), 확정된 완료(Committed), 오류로 멈춘 실패(Failed), 되돌려진 철회(Aborted) 상태를 거칩니다.
회원 테이블에서 회원번호와 이메일이 모두 유일해 둘 다 후보키였습니다. 이메일은 회원이 바꿀 수 있어서 기본키로 쓰면 참조하는 모든 테이블을 함께 고쳐야 합니다. 그래서 바뀌지 않는 회원번호를 기본키로 정하고, 이메일은 대체키로 남겨 UNIQUE 제약만 걸었습니다.
회원이 탈퇴해도 주문 기록은 회계 때문에 남겨야 했습니다. [주문]의 회원번호 외래키에 ON DELETE CASCADE 대신 ON DELETE SET NULL을 지정해, 회원 행을 지우면 주문은 남고 회원번호만 NULL이 되게 했습니다. 외래키가 없는 회원을 가리키는 일은 생기지 않으므로 참조 무결성도 지켜집니다.
콜센터 상담원은 고객 이름과 연락처만 보면 되는데, 고객 테이블에는 생년월일과 주소도 들어 있었습니다. 필요한 열만 고른 뷰를 만들고 상담원에게는 테이블이 아닌 뷰의 SELECT 권한만 줘서 보여 줄 정보만 보이게 했습니다. 어떤 뷰와 권한이 만들어져 있는지는 시스템 카탈로그를 조회해 정기적으로 점검합니다.