ER 다이어그램, 이제 “그리지” 말고 “쓰세요”

그래픽 도구로 ER(개체-관계) 다이어그램을 그리면, 테이블이 하나 늘 때마다 선을 다시 연결해야 하고 결국 그림이 실제 스키마와 어긋나게 됩니다. **Mermaid의 erDiagram**을 쓰면 다이어그램이 평범한 텍스트가 됩니다. 저장소 안에 함께 있고, diff에도 나타나며, GitHub README·PR·Notion을 비롯한 대부분의 Markdown 뷰어에서 자동으로 렌더링됩니다.

이 글은 훑어보며 바로 참고할 수 있는 레퍼런스입니다. 카디널리티 치트시트, 속성 문법, 완전한 실전 예제, 그리고 마지막으로 기존 SQL에서 이 모든 걸 자동 생성하는 방법까지 다룹니다.

최소 예제: 세 줄로 시작하기

erDiagram
    USERS ||--o{ POSTS : "has"

이것만으로 “USERS와 POSTS는 1대다(한 사용자가 0개 이상의 게시글을 가짐)“가 렌더링됩니다. 일반 형식은 다음과 같습니다.

<엔티티1> <왼쪽 카디널리티><선><오른쪽 카디널리티> <엔티티2> : "라벨"

미리 알아둘 점 하나: 콜론 뒤의 관계 라벨은 필수입니다. 텍스트를 보이고 싶지 않다면 : ""로 쓰세요. 아예 생략하면 문법 오류가 나며, 이것이 가장 흔한 첫 번째 실수입니다.

카디널리티 기호: 치트시트

erDiagram의 카디널리티는 까마귀발(crow’s foot) 표기법을 따릅니다. 기호는 항상 해당 엔티티 쪽을 향합니다.

왼쪽 기호오른쪽 기호의미
|oo|0 또는 1
||||정확히 1
}oo{0개 이상
}||{1개 이상

구체적인 조합으로 외우는 게 가장 빠릅니다.

문법의미
A ||--o{ BA는 1, B는 0개 이상 (가장 흔한 1대다)
A ||--|{ BA는 1, B는 반드시 1개 이상
A |o--o| B선택적 1대1
A ||--|| B엄격한 1대1
A }o--o{ B다대다 (중간 테이블을 넣기 전의 개념적 표현)

실선 vs 점선: 식별 관계 vs 비식별 관계

선 부분은 두 종류가 있습니다.

의미주로 쓰이는 곳
--식별 관계 (실선)자식의 기본키가 부모의 PK를 포함 (예: 주문 상세 항목)
..비식별 관계 (점선)자식이 일반 FK로 부모를 참조 (예: 게시글과 작성자)
ORDERS ||--|{ ORDER_ITEMS : "contains"     %% 식별 관계(실선)
USERS  ||..o{ POSTS       : "writes"       %% 비식별 관계(점선)

%%는 주석입니다. 식별 관계를 구분해서 쓸지, 아니면 실선으로 통일할지는 팀에서 정하세요. 둘 다 괜찮지만, 일관성이 있어야 다이어그램을 읽기 편합니다.

속성(컬럼) 정의하기

엔티티에 {} 블록을 붙이면 컬럼을 표 형태로 렌더링할 수 있습니다.

erDiagram
    USERS {
        int id PK "자동 증가"
        varchar(255) email UK "로그인 ID"
        varchar(100) name
        datetime created_at
    }

각 줄은 타입 이름 [키] ["주석"] 형식입니다.

  • PK / FK / UK이며, 쉼표로 구분해 여러 개를 조합할 수 있습니다(PK, FK) — 복합키를 가진 중간 테이블에 필수
  • 타입에 괄호를 포함할 수 있습니다. varchar(255)decimal(10)처럼요
  • 주석은 큰따옴표로 감쌉니다

실전 예제: 전자상거래 주문

지금까지 배운 문법을 전부 담은, 그대로 복사해서 쓸 수 있는 다이어그램입니다.

erDiagram
    USERS ||--o{ ORDERS : "places"
    ORDERS ||--|{ ORDER_ITEMS : "contains"
    PRODUCTS ||--o{ ORDER_ITEMS : "included in"

    USERS {
        int id PK
        varchar(255) email UK
        varchar(100) name
        datetime created_at
    }
    ORDERS {
        int id PK
        int user_id FK
        varchar(20) status
        datetime ordered_at
    }
    ORDER_ITEMS {
        int order_id PK, FK
        int product_id PK, FK
        int quantity
        decimal(10) unit_price
    }
    PRODUCTS {
        int id PK
        varchar(200) name
        decimal(10) price
    }

핵심은 ORDER_ITEMS입니다. 주문과 상품 사이의 다대다 관계를, 복합 기본키(두 개의 PK, FK 컬럼)를 가진 중간 테이블로 풀어냈고, “주문에는 반드시 상세 항목이 1개 이상 있다”는 비즈니스 규칙을 ||--|{ 카디널리티로 표현했습니다.

흔한 함정과 피하는 법

  • 관계 라벨은 필수입니다. 숨기고 싶으면 : ""
  • 엔티티 이름은 영문(ASCII)을 권장합니다. 비ASCII 이름의 렌더링은 환경마다 달라질 수 있으므로, 테이블 이름은 영어로 두고 현지어는 라벨이나 주석에 넣으세요
  • 다대다(}o--o{)는 개념 단계에서만 사용하세요. 구현 전에 중간 테이블로 풀어야 합니다
  • GitHub에서 렌더링이 안 되나요? 코드 블록 언어가 정확히 ```mermaid인지 확인하세요

CREATE TABLE 문에서 자동 생성하기

테이블이 10개를 넘어가면 이 문법을 손으로 쓰는 게 지루해집니다. 이미 DDL이 있다면 **SQL to ER 다이어그램 변환 도구**에 붙여넣기만 하세요 — 기본키, 외래키, 관계를 분석해서 Mermaid ER 다이어그램을 자동으로 생성합니다.

SQL to ER 도구로 CREATE TABLE 문에서 Mermaid ER 다이어그램 생성하기

모든 처리가 브라우저 안에서만 이루어지므로, 민감한 스키마 정보가 외부로 전송되지 않습니다. 기본 다이어그램을 생성한 뒤 위의 치트시트를 참고해 다듬으세요. 도구 자체에 대한 자세한 설명은 SQL DDL에서 ER 다이어그램 생성하는 방법을 참고하세요.

자주 묻는 질문

1대다 관계는 어떻게 쓰는 게 맞나요?

부모 ||--o{ 자식이 기본형입니다(부모 1개, 자식 0개 이상). “자식이 반드시 1개 이상 있어야 한다”가 실제 비즈니스 규칙일 때만 ||--|{를 쓰세요. 헷갈리면 ||--o{가 안전한 기본값입니다.

속성을 정의하지 않고 관계만 그릴 수 있나요?

네. {} 블록이 없어도 관계 라인에 등장한 엔티티는 렌더링됩니다. 설계 초기에는 관계만 그리고, 스키마가 안정된 뒤 속성 블록을 추가하는 방식이 실무에서 유용합니다.

Mermaid ER 다이어그램은 어디서 렌더링할 수 있나요?

GitHub(README, 이슈, PR), GitLab, Notion, VS Code(확장 기능 사용 시), Obsidian 등 대부분의 최신 Markdown 환경이 Mermaid 코드 블록을 기본으로 렌더링합니다. 그 외 환경에서는 Mermaid Live Editor로 SVG/PNG를 내보낼 수 있습니다.

다대다 관계를 그대로 구현할 수 있나요?

아니요. A }o--o{ B는 개념적 표기일 뿐입니다. 관계형 데이터베이스에서는 위 전자상거래 예제처럼 중간 테이블(복합 기본키 + 외래키 2개)이 필요합니다. 처음부터 다이어그램에 해소된 형태로 그려두면 구현 단계에서 재작업을 줄일 수 있습니다.