☰
面试官问:电商项目的商品表怎么设计?SPU和SKU到底怎么分?
2026/10/16 3:15:35 网站建设 项目流程
写在前面

这是我之前面试时被问到的一个真实问题:“你的线上超市项目里,商品表是怎么设计的?”

数据库表的设计是我们日常开发中经常涉及的内容,也是被面试官问的高频面试题。

但很多候选人的回答,往往只停留在“建几张表”的理论层面。一旦面试官追问:“如果是社区超市这种非标品多的场景呢?如果要兼顾线下拣货呢?”往往就卡壳了。

本文结合我接过的一个真实项目——「新万悦社区超市」,从真实的业务痛点出发,拆解我是如何用category、goods、goods_sku三张核心表,支撑起复杂的商品管理后台与 C 端展示的。


01. 为什么不能“一物一码”?

在设计“新万悦”的商品模块时,我面临的最大挑战是业务的复杂性。

社区超市不同于标准电商(如卖手机)。我们的商品既有标准的“可口可乐”,也有非标的“现杀鲈鱼”;既有线上的浏览下单,也有线下的货架拣货。

如果照搬简单的“一物一码”思维,把“300g菠菜”和“500g菠菜”当成两个完全独立的商品建表,后期在做价格调整和库存盘点时就会非常痛苦。

经过反复推敲,我最终确定了以SPU(标准化产品单元)+ SKU(库存量单位)为核心的三层架构。

02. 核心架构:SPU定骨架,SKU管血肉

在电商系统中,最忌讳的就是把所有属性都塞进一张大宽表。在我的设计中,我采用了经典的双层架构来解耦这个问题。

结合下面的后台编辑页面来看:

  • SPU (Standard Product Unit):商品的“骨架”

SPU 解决的是“这是什么商品”的问题。看原型图的上半部分,无论是“有机菠菜”还是“现杀鲈鱼”,它们的商品名称、副标题、封面图、品牌、产地,这些都是所有规格共有的属性。这些信息我只存一份在goods表中。这样做的好处是,当我想修改商品的详情页介绍时,只需要改一次,所有规格都会同步更新,保证了数据的一致性。

  • SKU (Stock Keeping Unit):商品的“血肉”

SKU 解决的是“具体卖哪个规格”的问题。请看原型图的下半部分表格。同一个 SPU 下,衍生出了不同的规格:

  • 规格差异:有的按重量卖(300g),有的按家庭装卖(2kg)。
  • 价格差异:300g 卖 12.8 元,2kg 卖 66.00 元。
  • 库存独立:300g 的可能还剩 100 份,但 2kg 的可能已经卖光了。

这些差异化的数据,全部下沉到goods_sku表中管理。每一行 SKU 记录,都通过goods_id关联回 SPU。

03. 亮点一:拒绝硬编码,用 JSON 拥抱“多变”的规格

面试官追问我:“超市的规格千奇百怪,有的按重量,有的按个数,你的 SKU 表怎么设计才能适应这种变化?”

很多初学者的回答是建spec_name和spec_value关联表。这种“三范式”设计在标准品电商里没问题,但在社区超市这种业务场景下,简直就是灾难。

因为超市的商品规格太“野”了:蔬菜按重量分,饮料按包装分,海鲜甚至可能按大小分。如果你用传统的关联表设计,每增加一种新的规格维度,你就得改代码、加字典表,非常僵化。

我的回答是:spec_json字段

我在goods_sku表中,直接设计了一个spec_json字段(varchar 类型),用来存储规格的键值对。

比如:

  • 300g菠菜,存的是:{"weight": "300g"}

  • 2KG家庭装存的是:{"weight": "2kg", "pack": "家庭装"}

这样做的好处是前端渲染极其灵活。前端拿到这个 JSON,可以直接循环渲染出规格选择器。不管你是“重量”还是“包装”,对前端来说只是一个 Key-Value 的展示,完全不用改接口。以后超市要卖“按个卖”的西瓜,数据库表结构一行代码都不用改。
04. 亮点二:面向线下的“实战级”字段预留

面试官追问:“你的项目是线上超市,那怎么考虑线下履约的效率?”

做线上超市项目,不能只盯着屏幕,还要盯着仓库。我在设计表结构时,特意预留了两个“不起眼”但至关重要的字段:location_code(货架号)和barcode(条形码)。

这两个字段是为了解决拣货效率问题的。当仓管人员拿着 PDA 去仓库拣货时,系统会生成一张拣货单。如果 SKU 表里没有location_code,拣货员就得满仓库找货。有了这个字段,系统可以直接告诉拣货员:“去 A-01-03 货架拿 2 份 300g 菠菜”。

为了配合这个业务,我在goods_sku表上专门建立了idx_location_code索引。当仓管人员按货架号批量导出要拣货的商品时,这个索引就能保证查询速度飞快,不会卡死数据库。

这就是我在做项目时坚持的原则:技术是为业务服务的,不要为了所谓的“范式”而牺牲了业务的灵活性。

05. 亮点三:无限级分类与 C 端体验
最后简单提一下分类设计。超市的分类通常很深:“生鲜 -> 水果 -> 热带水果 -> 芒果”。我在category表中使用了经典的parent_id自关联设计,配合sort排序字段,完美支撑了后台的拖拽排序和 C 端的侧边栏导航。

如上图所示,C 端左侧的一级分类导航,右侧的二级分类筛选,数据完全源自后台的树形结构。这种设计虽然传统,但在数据量可控(几千个分类)的情况下,是维护成本最低、扩展性最好的方案。

06.核心表结构设计

CREATE TABLE `category` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '分类ID(自增即可,数据量小)', `parent_id` int DEFAULT '0' COMMENT '父分类ID, 0为一级', `name` varchar(50) NOT NULL COMMENT '分类名称', `icon_url` varchar(255) DEFAULT NULL COMMENT '分类图标', `sort` int DEFAULT '0' COMMENT '排序值(越小越靠前)', `status` tinyint DEFAULT '1' COMMENT '状态: 1显示 0隐藏', `create_by` varchar(50) DEFAULT 'system' COMMENT '创建者', `update_by` varchar(50) DEFAULT 'system' COMMENT '更新者', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` tinyint DEFAULT '0' COMMENT '逻辑删除: 0正常 1删除', `version` int DEFAULT '0' COMMENT '乐观锁版本号', PRIMARY KEY (`id`), KEY `idx_parent_id` (`parent_id`) ) ENGINE=InnoDB AUTO_INCREMENT=2014 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品分类表'; CREATE TABLE `goods` ( `id` bigint NOT NULL COMMENT '商品ID(雪花算法)', `category_id` int NOT NULL COMMENT '分类ID', `name` varchar(100) NOT NULL COMMENT '商品名称', `sub_title` varchar(200) DEFAULT NULL COMMENT '副标题/卖点', `cover_image` varchar(255) NOT NULL COMMENT '封面图', `detail_images` text COMMENT '详情图(JSON数组)', `brand` varchar(50) DEFAULT NULL COMMENT '品牌', `origin` varchar(50) DEFAULT NULL COMMENT '产地', `unit` varchar(20) DEFAULT '件' COMMENT '单位: 件/斤/箱', `is_weighing` tinyint DEFAULT '0' COMMENT '是否称重品: 0否 1是', `min_stock_alert` int DEFAULT '10' COMMENT '库存预警阈值(SPU级默认, SKU可在inventory覆盖)', `status` tinyint DEFAULT '1' COMMENT '状态: 1上架 0下架', `is_recommend` tinyint DEFAULT '0' COMMENT '是否推荐: 0否 1是', `sales_count` int DEFAULT '0' COMMENT '累计销量(XXL-Job定时异步刷入)', `create_by` varchar(50) DEFAULT 'system' COMMENT '创建者', `update_by` varchar(50) DEFAULT 'system' COMMENT '更新者', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` tinyint DEFAULT '0' COMMENT '逻辑删除: 0正常 1删除', `version` int DEFAULT '0' COMMENT '乐观锁版本号', PRIMARY KEY (`id`), KEY `idx_category_status` (`category_id`,`status`), KEY `idx_recommend` (`is_recommend`,`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品SPU表'; CREATE TABLE `goods_sku` ( `id` bigint NOT NULL COMMENT 'SKU ID', `goods_id` bigint NOT NULL COMMENT '商品SPU ID', `spec_json` varchar(500) DEFAULT NULL COMMENT '规格JSON: {"weight":"500g"}', `price` decimal(10,2) NOT NULL COMMENT '售价', `original_price` decimal(10,2) DEFAULT NULL COMMENT '划线价', `barcode` varchar(64) DEFAULT NULL COMMENT '商品条码(标品扫码拣货用, P03)', `location_code` varchar(32) DEFAULT NULL COMMENT '货架库位(如 A-03-02, 拣货路径用, P02)', `weight_grams` int DEFAULT NULL COMMENT '预估重量(克, 称重品下单时按此预估计价)', `status` tinyint DEFAULT '1' COMMENT '状态: 1启用 0禁用', `create_by` varchar(50) DEFAULT 'system' COMMENT '创建者', `update_by` varchar(50) DEFAULT 'system' COMMENT '更新者', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` tinyint DEFAULT '0' COMMENT '逻辑删除: 0正常 1删除', `version` int DEFAULT '0' COMMENT '乐观锁版本号(守商品属性并发编辑)', PRIMARY KEY (`id`), UNIQUE KEY `uk_barcode` (`barcode`), KEY `idx_goods_id` (`goods_id`), KEY `idx_location_code` (`location_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品SKU表';

总结:那这道面试题如何回答呢?

如果面试时被问到“商品表怎么设计”,建议按照以下逻辑回答,能体现出你的业务思考深度:

  1. 先讲通用模型:首先明确回答采用SPU + SKU的双层模型。解释 SPU 存储公共属性(名称、详情),SKU 存储销售属性(价格、库存、规格),通过goods_id关联。

  2. 再讲灵活扩展:主动提到规格存储的难点。说明为了避免频繁改表,采用了 JSON 字段(如 spec_json)来存储多变的规格键值对,这样能极大提升系统的扩展性,适应非标品业务。

  3. 最后讲业务结合:这是加分项。结合你的项目特点,提到为了支持线下拣货,在 SKU 表中预留了 location_code(库位)和 barcode(条码)字段,并建立了相应索引。这能证明你不仅懂数据库设计,还懂真实的业务流程。

  4. 补充分类设计:简单提及使用 parent_id实现无限级分类,满足复杂的目录导航需求。

下一篇,我会继续拆解这个项目中的商品详情页的缓存设计方案,我们一起进步!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询