1. 说明

商品是电商系统的核心,这里我们一起来设计「商品」的数据库结构。

2. SKU

在这之前,我们需要先了解以下商品 SKU 的概念。

SKU = Stock Keeping Unit(库存量单位),也可以称之为「单品」。对一种商品而言,当其品牌、型号、配置、等级、花色、包装容量、单位、生产日期、保质期、用途、价格、产地等属性中任一属性与其他商品存在不同时,可称为一个单品。

为了更好地理解商品与商品 SKU 的关系,我们拿天猫上的商品作为例子:

file

在这个例子中,商品就是 iPhone,不同的版本、不同的存储容量所对应的具体型号就是这个商品的 SKU,比如 iPhone 7 - 无需合约版 - 玫瑰金色 - 32GB 就是一个 SKU,iPhone 7 - 无需合约版 - 红色 - 128GB 是另外一个 SKU,不同的 SKU 价格可能不一样,库存也不一样。

商家在管理库存的时候,就是以 SKU 为单位来操作的,比如入库时会写清楚「购入 iPhone 7 - 无需合约版 - 玫瑰金色 - 32GB 10 台,购入 iPhone 7 - 无需合约版 - 红色 - 128GB 10 台」,而不是「购入 iPhone 7 20 台」。

3. 数据结构设计

我们先实现一个维度的 SKU。多维度的 SKU 只不过运营层面工作流会大一些,简而言之就是编辑需要录入更多的商品类型而已,这里的数据结构和技术方案,也适用于多维度 SUK 的。

3.1 数据库表设计

我们会有两个数据表:

  • products - 产品信息表,对应数据模型 Product
  • products_skus - 产品的 SKU 表,对应数据模型 ProductSku

3.2 字段设计

products 表:

字段名称 描述 类型 加索引缘由
id 自增长 unsigned int 主键
title 商品名称 varchar -
description 商品详情 text -
image 商品封面图片文件路径 varchar -
on_sale 商品是否正在售卖 tiny int, default 1 -
rating 商品平均评分 float, default 5 -
sold_count 销量 unsigned int, default 0 -
review_count 评价数量 unsigned int, default 0 -
price SKU 最低价格 decimal -

商品本身没有固定的价格,我们在商品表放置 price 字段的目的是方便用户搜索、排序。

product_skus 表:

字段名称 描述 类型 加索引缘由
id 自增长 unsigned int 主键
title SKU 名称 varchar -
description SKU 描述 varchar -
price SKU 价格 decimal -
stock 库存 unsigned int -
product_id 所属商品 id unsigned int 外键

电商项目中与钱相关的小数点的字段一律使用 decimal 类型,而不是 float 和 double,后面两种类型在做小数运算时有可能出现精度丢失的问题,这在电商系统里是绝对不允许出现的。

4. 多维度 SKU

多维度其实也并不复杂,再添加一个 product_sku_attributes 表,字段如下:

  • id
  • product_id
  • name

然后给 SKU 加一个 attributes 字段。

假如有一个 id = 3 的商品 iPhone X,有 3 个 product_sku_attributes:

[
    ['id' => 1, 'product_id' => 1, 'name' => '套餐类型'],
    ['id' => 2, 'product_id' => 1, 'name' => '颜色'],
    ['id' => 3, 'product_id' => 1, 'name' => '内存']
]

新建 SKU 的时候,attributes 值为:

[
    ['id' => 1, 'value' => '套餐一'],
    ['id' => 2, 'value' => '土豪金'],
    ['id' => 3, 'value' => '256G'],
]

在逻辑上并不复杂。

有时候不需要一味地最求数据库设计范式,特别是 MySQL 加入 JSON 支持之后,只要不涉及到搜索查询的都可以往 JSON 字段里丢。