웹/앱 개발에서 카테고리 구조(분류 체계)를 DB로 설계할 때, “가장 쉽고 편한 방법”을 원하신다면
프로젝트 규모, 데이터 양, 조회/추가/수정/삭제 패턴을 고려해 적절한 방식을 쓰는 게 중요합니다.
실제 현업에서 많이 쓰는 방법과 각각의 특징, 특히 개발이 쉽고 유지보수가 편한 순서로 정리해 드리겠습니다.
1. Adjacency List (가장 쉽고 직관적인 방식)
- 가장 많이 쓰고, DB에서도 구현이 제일 단순합니다.
id | name | parent_id |
1 | 전자제품 | NULL |
2 | 컴퓨터 | 1 |
3 | 노트북 | 2 |
4 | 스마트폰 | 1 |
5 | 가전 | 1 |
6 | 세탁기 | 5 |
* parent_id가 NULL이면 루트 카테고리.
* 하위 카테고리는 parent_id로 부모 카테고리를 참조.
장점
- 구조 단순, 이해 쉽고 구현 빠름.
- 수정/추가/삭제가 간단.
단점
- 트리 전체나 특정 깊이까지 조회 시 재귀 쿼리가 필요.
- MySQL/MariaDB 8.0+의 WITH RECURSIVE 같은 재귀 CTE로 해결 가능.
사용
소규모~중규모, 기능 단순한 프로젝트에는 이 방식이 가장 추천
ex) 카테고리 깊이가 2~3단계 정도인 쇼핑몰, 블로그
2. Nested Set
- 왼쪽/오른쪽(lft/rgt) 값으로 계층을 표현.
id | name | lft | rgt |
1 | 전자제품 | 1 | 12 |
2 | 컴퓨터 | 2 | 5 |
3 | 노트북 | 3 | 4 |
4 | 스마트폰 | 6 | 7 |
5 | 가전 | 8 | 11 |
6 | 세탁기 | 9 | 10 |
* 하위 카테고리 조회가 아주 빠름: WHERE lft > 부모.lft AND rgt < 부모.rgt.
* 트리 변경(삽입/삭제) 시 다른 노드의 lft/rgt 값 대규모 갱신 필요 → 관리 어려움.
추천 상황
- 조회 빈도 많고, 수정 거의 없는 정적 트리 구조.
3. Materialized Path
- 경로를 문자열로 저장 (예: 1/2/3).
id | name | path |
1 | 전자제품 | /1/ |
2 | 컴퓨터 | /1/2/ |
3 | 노트북 | /1/2/3/ |
* 하위 카테고리: LIKE '/1/2/%'로 쉽게 조회.
* 부모 변경 시 하위 모든 경로를 업데이트해야 해서 트리 변경이 잦으면 번거로움.
4. Closure Table
- 트리 구조와 관계를 별도 테이블에 저장.
ancestor | descendant | depth |
1 | 1 | 0 |
1 | 2 | 1 |
1 | 3 | 2 |
2 | 2 | 0 |
2 | 3 | 1 |
3 | 3 | 0 |
* 모든 경로를 미리 저장하므로 빠르게 조상/자손 조회 가능.
* 테이블 수 늘고, 추가/삭제 시 관계 추가/삭제 처리 필요.
추천
- 복잡한 계층 구조, 빈번한 상하위 조회에 유리.
가장 쉽고 추천
- 소규모/중규모, 깊이가 얕은(1~3단계) 카테고리
→ Adjacency List (parent_id 필드 방식) - MySQL 8.0+라면 재귀 CTE로 계층 트리도 쉽게 조회 가능.
- 유지보수도 쉽고, 신규 개발자도 바로 이해 가능.
MySQL 테이블 구조 예제
CREATE TABLE category (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT DEFAULT NULL,
FOREIGN KEY (parent_id) REFERENCES category(id)
);
- category 테이블
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, 0 AS depth
FROM category
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM category c
INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree;
- 하위 카테고리 모두 조회(MySQL 8.0+)
'MySQL(MariaDB)' 카테고리의 다른 글
MySQL에서 사용하는 데이터 타입(Data Type) 정의 (26) | 2025.07.21 |
---|---|
트랜잭션(Transaction) 이란? (60) | 2025.07.17 |
MySQL의 가장 기본이자 중요한 개념인 CRUD 설명 (29) | 2025.07.09 |
MySQL 사용자 생성 및 권한 설정 (22) | 2025.07.08 |
DB(Database/데이터베이스)의 종류는? (42) | 2025.06.30 |