🗂️ 为E-Commerce应用设计可扩展的分类系统
Source: Dev.to

在构建电子商务应用时,分类起初看起来很简单——但当你的商品数量增长,业务需求出现以下情况时:
- 子类别
- 嵌套菜单
- 面包屑导航
- SEO友好URL
- 轻松重新排序
本 README 说明了在真实系统中使用的可扩展、可投入生产的分类设计,且避免了过度设计。
常见错误
许多应用程序从独立的表开始:
categories
sub_categories
sub_sub_categories
当出现以下情况时,这种做法会立即失效:
- 需要更深的层级
- 层级结构发生变化
- 查询变得复杂

可扩展方案(单一类别表)
使用 一张表 并自引用。
CREATE TABLE categories (
id UUID PRIMARY KEY, -- or BIGINT
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) UNIQUE NOT NULL,
parent_id UUID REFERENCES categories(id),
level INT NOT NULL,
path VARCHAR(500) NOT NULL,
sort_order INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
这支持 无限层级嵌套 并且查询简洁。
层级工作原理
示例结构
Electronics
└── Mobiles
├── Smartphones
└── Feature Phones
存储的数据
| id | name | parent_id | level | path | sort_order |
|---|---|---|---|---|---|
| 1 | 电子产品 | NULL | 0 | 1 | 1 |
| 2 | 手机 | 1 | 1 | 1/2 | 1 |
| 3 | 智能手机 | 2 | 2 | 1/2/3 | 1 |
| 4 | 功能手机 | 2 | 2 | 1/2/4 | 2 |
Source: …
字段拆解(重要部分)
1️⃣ slug – URL 友好的标识符
slug 是用于 URL 的可读字符串。
"Smart Phones" → "smart-phones"
使用场景:
/category/electronics/mobiles/smartphones
为什么 slug 很重要
- 对 SEO 友好
- 稳定的 URL
- 不暴露内部 ID
2️⃣ level – 分类的层级深度
level 表示分类所在的层级深度。
level 0 = 根分类
level 1 = 子分类
level 2 = 子子分类
存在的原因
- 在首页只显示顶层分类
- 限制最大层级深度
- 简化过滤
查询示例
SELECT * FROM categories WHERE level = 0;
3️⃣ path – 完整层级路径(物化路径)
path 保存从根节点到当前节点的 完整血缘。
Electronics → Mobiles → Smartphones
path = "1/2/3"
为什么它很强大
- 无需递归即可获取整个子树
- 轻松构建面包屑导航
- 生成 SEO 友好的 URL
查询示例
SELECT * FROM categories WHERE path LIKE '1/2/%';
4️⃣ sort_order – 显示顺序控制(非层级)
sort_order 决定分类在 UI 中的显示顺序。
- 没有它 → 顺序不可预测
- 有了它 → 业务可控制的顺序
查询示例
SELECT * FROM categories ORDER BY sort_order ASC;
使用场景
- 导航栏排序
- 推荐分类
- 季节性重新排列
为什么要同时使用 level + path?
| 用例 | level | path |
|---|---|---|
| 顶层过滤 | ✅ | ❌ |
| 最大深度验证 | ✅ | ❌ |
| 子树查询 | ❌ | ✅ |
| 面包屑 | ❌ | ✅ |
| SEO URL | ❌ | ✅ |
它们解决的是不同的问题,而不是重复。
产品关联
产品通常属于 叶子类别。
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) UNIQUE NOT NULL,
price NUMERIC(10,2) NOT NULL,
category_id UUID REFERENCES categories(id)
);
最终建议
- ✅ 单一
categories表 - ✅
parent_id用于结构 - ✅
level用于深度逻辑 - ✅
path用于快速读取 - ✅
slug用于简洁 URL - ✅
sort_order用于 UI 控制
此设计可从创业 MVP 扩展到大型市场而无需更改模式。
Interview One‑Liner
可扩展的分类系统使用 self‑referencing table 与 materialized paths,以支持 unlimited depth、fast reads、clean URLs 和 UI‑controlled ordering。