데이터 베이스/설계 1편, 현대적 데이터 모델링 완전 정복

Ch07. 논리적 모델링(4) - 식별, 비식별 관계의 일대다

webmaster 2026. 6. 27. 13:49

게시글(BOARD) 댓글(COMMENT) 관계를 예로 들어보자. 하나의 게시글에는 여러 댓글이 달릴 있다. (1:N) 관계를 식별 관계, 비식별 관계로 각각 모델링 해보면서 장단점을 알아보자.

 

비식별 관계

방식은 자식 테이블인 COMMENT 자신만의 고유한 기본 (comment_id) 가지는 구조다.

ERD

  • ERD에서 비식별 관계는 점선으로 표시된다. 식별 관계는 실선으로 표시된다.
DROP TABLE IF EXISTS comment_non_identifying;
DROP TABLE IF EXISTS board_non_identifying;

CREATE TABLE board_non_identifying (
	board_id BIGINT NOT NULL AUTO_INCREMENT,
	title VARCHAR(255) NOT NULL,
	PRIMARY KEY (board_id)
);

CREATE TABLE comment_non_identifying (
	comment_id BIGINT NOT NULL AUTO_INCREMENT, -- 독립적인 PK
	board_id BIGINT NOT NULL, -- 일반 컬럼 + FK
	content TEXT NOT NULL,
	PRIMARY KEY (comment_id),
	CONSTRAINT fk_comment_board_non FOREIGN KEY (board_id)
		REFERENCES board_non_identifying (board_id)
);
  • comment_non_identifying 테이블은 "comment_id"라는 독립적인 대리 키(Surrogate Key)를 PK로 사용한다.
  • "board_id(FK)"는 어떤 게시글에 달린 댓글인지를 나타내는 단순 외래 키일뿐, PK의 일부가 아니다.

장점

  • 단순하고 명확하다: "comment_id" 하나만 알면 특정 댓글을 조회, 수정, 삭제할 수 있다. PK가 단순하여 관리가 매우 쉽다.
  • 유연하다: 만약 비즈니스 로직이 변경되어 댓글을 다른 게시글로 옮겨야 하는 상황이 생기면, "board_id(FK)" 값만 UPDATE 하면 그만이다.
    • 관계가 느슨하게 연결되어 있어 변화에 유연하다.
  • ORM 친화적이다: JPA/Hibernate 같은 ORM 기술은 이런 단순한 대리 키 구조에서 가장 자연스럽고 효율적으로 동작한다.

단점

  • PK만 봐서는 부모와의 관계를 직관적으로 알기 어렵다. (큰 단점은 아니다)

 

데이터 입력 조회

-- 데이터 입력
INSERT INTO board_non_identifying (title) VALUES ('첫 번째 게시글'); -- board_id:
INSERT INTO board_non_identifying (title) VALUES ('두 번째 게시글'); -- board_id:


INSERT INTO comment_non_identifying (board_id, content) VALUES (1, '1번 글의 첫 댓글입니다.'); -- comment_id: 1
INSERT INTO comment_non_identifying (board_id, content) VALUES (1, '1번 글의 두번째 댓글입니다.'); -- comment_id: 2

INSERT INTO comment_non_identifying (board_id, content) VALUES (2, '2번 글의 첫댓글입니다.'); -- comment_id: 3

 

board_non_identifying 테이블 데이터
comment_non_identifying 테이블 데이터

  • 결과를 보면 알 수 있듯이, 각 댓글은 "board_id"와 관계없이 "comment_id"라는 고유한 값(1, 2, 3)으로 완벽하게 식별된다.
  • 댓글을 조회하거나 수정할 때 "comment_id=2"와 같이 하나의 값만 사용하면 되므로 매우 직관적이다.

 

식별 관계

 

방식은 자식 테이블인 COMMENT 부모의 기본 (board_id) 물려받아 자신의 기본 키의 일부로 삼는 구조다.

ERD

  • ERD에서 식별 관계는 실선으로 표시된다. 비식별 관계는 점선으로 표시된다.
DROP TABLE IF EXISTS comment_identifying;
DROP TABLE IF EXISTS board_identifying;

CREATE TABLE board_identifying (
	board_id BIGINT NOT NULL AUTO_INCREMENT,
	title VARCHAR(255) NOT NULL,
	PRIMARY KEY (board_id)
);

CREATE TABLE comment_identifying (
	board_id BIGINT NOT NULL, -- PK의 일부 + FK
	comment_no BIGINT NOT NULL, -- PK의 일부, 해당 board_id 내에서 순차 증가
	content TEXT NOT NULL,
	PRIMARY KEY (board_id, comment_no), -- 복합 기본 키 (Composite PK)
	CONSTRAINT fk_comment_board_iden FOREIGN KEY (board_id)
		REFERENCES board_identifying (board_id)
);
  • comment_identifying 테이블의 PK는 "(board_id, comment_no)" 두 개의 컬럼으로 구성된 복합키다.
    • 일대다 관계이므로 부모로부터 받은 PK인 "board_id" 만으로는 PK를 구성할 수 없다.
      • "comment_no" 같은 추가 정보가 필요하다.
    • "board_id"는 PK이면서 동시에 board_identifying 테이블을 참조하는 FK다.
  • "comment_no"는 댓글 순서에 맞추어 애플리케이션에서 번호를 만들어야 한다(채번). 데이터베이스가 제공하는 자동 증가값(auto increment)을 사용할 수 없다

 

장점

  • PK 자체가 비즈니스 의미를 가진다: "(board_id=10, comment_no=3)"이라는 PK는 "10번 게시글의 3번째 댓글"이라는 명확한 의미를 가진다.
  • 데이터 정합성 강화: 이 구조에서는 "board_id" 없이 comment가 존재할 수 없다는 것이 명확하게 표현된다.
  • 쿼리 최적화 가능성: 게시글과 댓글을 항상 같이 조회하는 경우, 복합키 인덱스가 효율적으로 사용될 수 있다.

 

단점

  • 복잡하다: 복합키는 관리하기가 번거롭다. 조회, 수정, 삭제 시 항상 두 개의 키 값을 모두 사용해야 한다.
  • 유연성이 없다: 부모의 PK가 자식 PK의 일부가 되므로, 댓글을 다른 게시글로 옮기는 등의 비즈니스 요구사항 변경에 대응하기 매우 어렵다.
    • PK 값 자체를 변경해야 하기 때문이다.
  • 확장성이 떨어진다: 만약 댓글에 "reply"라는 대댓글 기능이 추가된다면, PK 구조가 계속해서 길어지고 복잡해지는 문제가 발생한다.
  • ORM 매핑의 복잡성: ORM에서 복합키를 매핑하려면 별도의 식별자 클래스를 만드는 등 추가적인 작업이 필요하다.

 

데이터 입력 조회

-- 데이터 입력
INSERT INTO board_identifying (title) VALUES ('첫 번째 게시글'); -- board_id: 1
INSERT INTO board_identifying (title) VALUES ('두 번째 게시글'); -- board_id: 2

-- 애플리케이션 레벨에서 comment_no를 계산해서 넣어주어야 한다.
INSERT INTO comment_identifying (board_id, comment_no, content) VALUES (1, 1, '1번 글의 첫 댓글입니다.');
INSERT INTO comment_identifying (board_id, comment_no, content) VALUES (1, 2, '1번 글의 두 번째 댓글입니다.');
INSERT INTO comment_identifying (board_id, comment_no, content) VALUES (2, 1, '2번 글의 첫 댓글입니다.');

board_identifying 테이블의 데이터
comment_identifying 테이블의 데이터

  • 여기서는 "comment_no" 컬럼만 보면 "1"이라는 값이 중복된다.
    • 하지만 기본 키는 "(board_id, comment_no)" 두 개를 합친 복합키이므로 "(1, 1)", "(1, 2)", "(2, 1)"은 모두 고유한 값으로 인정된다.
  • 특정 댓글을 조회하려면 "WHERE board_id = 1 AND comment_no = 2" 같이 항상 개의 값을 조건으로 사용해야 한다.