본문 바로가기
개발 경험 기록/데이터베이스

PRIMARY KEY, 칼럼의 속성일까 테이블의 속성일까?

by 시니성 2025. 1. 17.

최근 제가 개발한 DDL-DSL 라이브러리에 ALTER 문 지원을 추가하는 작업을 진행하면서, 어찌보면 당연히 알아야할 지식이지만, 부끄럽게도 PRIMARY KEY 제약조건에 이제야 좀 더 명확히 알게 된 부분이 있어 기록해봅니다.

자칫 오해할 수 있는 PRIMARY KEY의 성격

대부분 테이블을 생성할 때 다음과 같이 PRIMARY KEY를 지정합니다.

CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(200)
);

또는 복합키를 사용할 때는 이렇게 합니다.

CREATE TABLE orders (
    order_year INT,
    order_sequence INT,
    customer_id INT,
    amount DECIMAL(10,2),
    PRIMARY KEY (order_year, order_sequence)
);

이 두 가지 문법이 공존하다 보니, PRIMARY KEY가 마치 개별 칼럼의 속성처럼 느껴지기 쉽습니다.
특히 단일 칼럼을 PRIMARY KEY로 지정할 때는 더욱 그렇죠.

부끄럽게도 어렴풋 하던 개념을 이제서야 알게됐습니다..

하지만 DDL-DSL에 ALTER TABLE 지원을 추가하는 과정에서, 제 머릿속에서 프라이머리키가 속한 개념의 바운더리가 너무 어렴풋하게 잡혀있다는 것도 알았습니다.
다음과 같은 상황을 고려해 볼까요?

ALTER TABLE t ALTER COLUMN d VARCHAR(800) PRIMARY KEY;

이 구문은 언뜻 보기에 타당해 보이지만, 실제로는 동작하지 않습니다. 왜일까요?

그 이유는 PRIMARY KEY가 실제로는 테이블 레벨의 제약조건(table-level constraint)이기 때문입니다.
이는 다음과 같은 특징에서 명확하게 드러납니다.

  1. 제약조건으로서의 성격: PRIMARY KEY는 FOREIGN KEY, CHECK 제약조건과 마찬가지로 테이블의 제약조건으로 관리됩니다.
  2. 테이블당 유일성: 하나의 테이블에는 오직 하나의 PRIMARY KEY만 존재할 수 있습니다.
  3. 복합키 지원: 여러 칼럼을 하나의 PRIMARY KEY로 지정할 수 있다는 것 자체가, 이것이 개별 칼럼의 속성이 아님을 보여줍니다.

올바른 접근 방식

따라서 PRIMARY KEY를 변경하려면, 다른 제약조건을 다루는 것과 같은 방식으로 접근해야 합니다.

-- 기존 PRIMARY KEY 제거
ALTER TABLE t DROP CONSTRAINT [기존_PK_이름];

-- 새로운 PRIMARY KEY 추가
ALTER TABLE t ADD CONSTRAINT PK_t_new PRIMARY KEY (d);

DDL-DSL에의 적용

이러한 이해를 바탕으로, DDL-DSL의 ALTER TABLE 지원은 다음과 같은 방식으로 구현되어야 함을 알 수 있었습니다.

// PRIMARY KEY 변경을 위한 별도의 명확한 인터페이스 제공
interface TableConfigCreator {
    fun alterTable(
        tableName: String,
        operations: List<AlterTableOperation>,
        dialect: SqlDialect
    ): String
}

sealed class AlterTableOperation {
    data class ModifyColumn(/* ... */) : AlterTableOperation()
    data class AddConstraint(/* ... */) : AlterTableOperation()
    data class DropConstraint(/* ... */) : AlterTableOperation()
    // ...
}

마치며

이번 개발 경험을 통해, 데이터베이스의 제약조건이 가진 본질적인 성격에 대해 좀 더 명확히 이해하게 되었습니다.
CREATE TABLE 문에서 칼럼 정의와 함께 PRIMARY KEY를 지정할 수 있다는 것은 단지 문법적 편의성을 위한 것일 뿐, 실제로는 테이블 수준에서 관리되는 제약조건임을 명확히 인식하게 되었습니다.
이런 기본적인 것을 이제야 명확히 알게 된 게, 조금 부끄럽긴하지만 이를 통해 저는 SQL 중 DDL을 다루는 도구나 라이브러리를 설계할 때도 더 명확하고 올바른 추상화를 할 수 있게 되었다고 생각합니다.

곧 DDL-DSL 라이브러리의 Alter 문 지원 개발기로 찾아뵙겠습니다. 감사합니다.

728x90