商品规格数据结构与商品表结构分析

商品规格数据结构与商品表结构分析:

  • 1. 商品规格数据结构
    • 1.1 规格属性内容
    • 1.2 横表与数表
    • 1.3 表结构
      • 1.3.1 SpecGroup规格组
      • 1.3.2 SpecParam规格参数
    • 1.4 从面向对象的角度分析
  • 2. 商品表结构分析
    • 2.1 SPU和SKU
    • 2.2 表结构
      • 2.2.1 表结构分析
      • 2.2.2 SPU表
        • 2.2.2.1 spu表结构
        • 2.2.2.2 spu_detail 表结构
        • 2.2.2.3 spu中的规格参数
          • 2.2.2.3.1 generic_spec字段
          • 2.2.2.3.2 special_spec字段
      • 2.2.3 SKU表
        • 2.2.3.1 sku表结构
        • 2.2.3.2 stock库存表
        • 2.2.3.3 sku中的规格参数
          • 2.2.3.3.1 indexes字段
          • 2.2.3.3.2 own_spec字段

1. 商品规格数据结构

商品中都有属性,不同商品,属性往往不同。

1.1 规格属性内容

在生活中,我们很容易发现,虽然商品不同,规格不同。但是统一分类的商品,比如都是手机,其规格是一致的,但是值不一样。也就是说,商品的规格参数应该是与分类绑定的。每一个分类都有统一的规格参数模板,但不同商品其参数值可能不同

因此:

  • 规格参数的名称(key)与值(value)应该分开来保存;
  • 一个分类,对应一套规格参数模板,只有规格参数key,没有值;
  • 一个分类对应多个商品,每个商品的规格值不同,每个商品对应一套规格的值。

1.2 横表与数表

值我们暂且不管,新增商品时,再来填写规格参数值即可,我们先思考规格参数模板(key)该如何设计。
先看下规格参数的结构:
商品规格数据结构与商品表结构分析_第1张图片

  • 规格数据首先要分组,组内再有不同的规格参数
  • 不同分类,其分组名称也不同
  • 不停分类,组内属性也不同
    这样就意味着:有多少分类,就有多少分组。
    如果按照传统设计,我们会以规格参数作为数据库字段名。如品牌、型号都是字段,那么表的字段就会无限多。这样的表称为横表。一条信息,描述所有数据。例如:
    在这里插入图片描述
    我们不这样做,我们一条信息,只描述一条规格属性,也就是把规格参数作为字段的值,而非字段本身。这样的设计称为竖表设计。例如:
    商品规格数据结构与商品表结构分析_第2张图片
    不过,规格和规格组也要单独保存,都采用竖表设计。所以我们有两张表:
    商品规格数据结构与商品表结构分析_第3张图片
    如图:
    商品规格数据结构与商品表结构分析_第4张图片

1.3 表结构

1.3.1 SpecGroup规格组

规格参数分组表:tb_spec_group

CREATE TABLE `tb_spec_group` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `cid` bigint(20) NOT NULL COMMENT '商品分类id,一个分类下有多个规格组',
  `name` varchar(50) NOT NULL COMMENT '规格组的名称',
  PRIMARY KEY (`id`),
  KEY `key_category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='规格参数的分组表,每个商品分类下有多个规格参数组';

商品规格数据结构与商品表结构分析_第5张图片

1.3.2 SpecParam规格参数

规格参数表:tb_spec_param

CREATE TABLE `tb_spec_param` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `cid` bigint(20) NOT NULL COMMENT '商品分类id',
  `group_id` bigint(20) NOT NULL,
  `name` varchar(255) NOT NULL COMMENT '参数名',
  `numeric` tinyint(1) NOT NULL COMMENT '是否是数字类型参数,true或false',
  `unit` varchar(255) DEFAULT '' COMMENT '数字类型参数的单位,非数字类型可以为空',
  `generic` tinyint(1) NOT NULL COMMENT '是否是sku通用属性,true或false',
  `searching` tinyint(1) NOT NULL COMMENT '是否用于搜索过滤,true或false',
  `segments` varchar(1000) DEFAULT '' COMMENT '数值类型参数,如果需要搜索,则添加分段间隔值,如CPU频率间隔:0.5-1.0',
  PRIMARY KEY (`id`),
  KEY `key_group` (`group_id`),
  KEY `key_category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='规格参数组下的参数名';

商品规格数据结构与商品表结构分析_第6张图片

通用属性

用一个布尔类型字段来标记是否为通用:

  • generic来标记是否为通用属性:
    • true:代表通用属性
    • false:代表sku特有属性

搜索过滤

与搜索相关的有两个字段:

  • searching:标记是否用作过滤
    • true:用于过滤搜索
    • false:不用于过滤
  • segments:某些数值类型的参数,在搜索时需要按区间划分,这里提前确定好划分区间
    • 比如电池容量,0 ~ 2000mAh,2000mAh ~ 3000mAh,3000mAh ~ 4000mAh

数值类型

某些规格参数可能为数值类型,这样的数据才需要划分区间,我们有两个字段来描述:

  • numberic:是否为数值类型
    • true:数值类型
    • false:不是数值类型
  • unit:参数的单位

1.4 从面向对象的角度分析

我们现在要表示规格参数的key,不要值。
如果用java对象表示:首先可以知道其可以分成 组 和 组内属性 两部分。 组 和 组内属性 分别是两类事物。
对组进行描述:对组内的共同特征进行抽取,可以采用java中的 类(class Group) 进行描述。将主体、基本信息、操作系统等看成类中的name字段,将每一个分组下对应的多个参数(主体下的 型号、入网年份)看成类中的List params,同时,每个组也会有一个属于自己的id来标识自己。

商品规格数据结构与商品表结构分析_第7张图片
对组内属性进行描述 :上述的List params 又是一个新的事物, 同样也可采用 类(class Param) 的概念进行描述。同样有name(参数名)、id字段,同时还要有一个groupId来说明这些参数属于哪个组分类下的,这样就做到了Group表和Param表相互关联。同时,Group表中也应添加categoryId来说明这些规格组是属于哪个商品分类下的。但是,再考虑,规格参数属性里应该也要加入是否为数值类型的字段;若是,那还会衍生出一个新的字段Unit;由于有一些规格参数的字段将来是要做搜索的,因此还应该有判断该参数是否为搜索字段;如果可以搜索,同时又是数值类型,那还会有一个segment字段(字符串类型)。到此为止,规格参数就描述清楚了。

2. 商品表结构分析

乐优商城是一个全品类的电商网站,因此商品的种类繁多,每一件商品,其属性又有差别。为了更准确描述商品及细分差别,抽象出两个概念:SPU和SKU。

2.1 SPU和SKU

  • SPU:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集

  • SKU:Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品

以图为例:
商品规格数据结构与商品表结构分析_第8张图片

  • 本页的 华为Mate10 就是一个商品集(SPU)
  • 因为颜色、内存等不同,而细分出不同的Mate10,如亮黑色128G版。(SKU)

可以看出:

  • SPU是一个抽象的商品集概念,为了方便后台的管理
  • SKU才是具体要销售的商品,每一个SKU的价格、库存可能会不一样,用户购买的是SKU而不是SPU
  • 同一个SPU下的SKU有共有属性,也有特有属性

2.2 表结构

2.2.1 表结构分析

其实,SKU的特有属性是商品规格参数的一部分。规格参数我们已经提前设计好了,每一个分类都有自己的规格参数。因此我们在设计商品表的时候不要设计特有属性,这些特性设计到规格参数里了。因此规格参数表里的generic字段对 特有属性还是通用属性 进行了区分。
商品规格数据结构与商品表结构分析_第9张图片
也就是说,我们没必要单独对SKU的特有属性进行设计,它可以看做是规格参数中的一部分。这样规格参数中的属性可以标记成两部分:

  • 所有sku共享的规格属性(称为通用属性),我们记录在spu表中
  • 每个sku不同的规格属性(称为特有属性),我们记录在sku表中
    商品规格数据结构与商品表结构分析_第10张图片

2.2.2 SPU表

2.2.2.1 spu表结构

CREATE TABLE `tb_spu` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'spu id',
  `title` varchar(255) NOT NULL DEFAULT '' COMMENT '标题(商品名称)',
  `sub_title` varchar(255) DEFAULT '' COMMENT '子标题',
  `cid1` bigint(20) NOT NULL COMMENT '1级类目id',
  `cid2` bigint(20) NOT NULL COMMENT '2级类目id',
  `cid3` bigint(20) NOT NULL COMMENT '3级类目id',
  `brand_id` bigint(20) NOT NULL COMMENT '商品所属品牌id',
  `saleable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否上架,0下架,1上架',
  `valid` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效,0已删除,1有效',
  `create_time` datetime DEFAULT NULL COMMENT '添加时间',
  `last_update_time` datetime DEFAULT NULL COMMENT '最后修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=208 DEFAULT CHARSET=utf8 COMMENT='spu表,该表描述的是一个抽象的商品,比如 iphone8';

由于SPU表中某些字段的值非常大,比如商品描述。

因此为了不影响spu表的性能及查询速度,我们对表做了垂直拆分,将SPU的详情放到了另一张表:tb_spu_detail

商品规格数据结构与商品表结构分析_第11张图片
注:

  • 垂直拆分:表字段过多,实现数据的解耦
  • 水平拆分:表数据量多(一张表有1万条数据,水平拆分成两个表,每个表5千条数据)数据库查询时做排序较麻烦,不过现在有很多中间件帮我们实现分表 查询、排序等。用在 订单表中,订单数据量很大,一张表存不下,必然要做水平拆分。

2.2.2.2 spu_detail 表结构

CREATE TABLE `tb_spu_detail` (
  `spu_id` bigint(20) NOT NULL,
  `description` text COMMENT '商品描述信息',
  `generic_spec` varchar(3000) NOT NULL DEFAULT '' COMMENT '通用规格参数数据',
  `special_spec` varchar(1000) NOT NULL COMMENT '特有规格参数及可选值信息,json格式',
  `packing_list` varchar(1000) DEFAULT '' COMMENT '包装清单',
  `after_service` varchar(1000) DEFAULT '' COMMENT '售后服务',
  PRIMARY KEY (`spu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.2.2.3 spu中的规格参数

前面讲过规格参数与商品分类绑定,一个分类下的所有SPU具有类似的规格参数。SPU下的SKU可能会有不同的规格参数,因此:

  • SPU中保存通用的规格参数信息。
  • SKU中保存特有规格参数。
2.2.2.3.1 generic_spec字段

generic_spec:保存通用规格参数信息的值,这里为了方便查询,使用了json格式。
商品规格数据结构与商品表结构分析_第12张图片
json结构,其中都是键值对:

  • key:对应的规格参数的spec_param的id
  • value:对应规格参数的值
2.2.2.3.2 special_spec字段

由于SPU下的每一个sku,其值也都不一样,所以值会有很多,形成数组。

因此我们在SPU中,会把特有属性的所有值都记录下来,形成一个数组:
商品规格数据结构与商品表结构分析_第13张图片
也是json结构:

  • key:规格参数id
  • value:spu属性的数组

问题:特有规格参数应该在sku中记录才对,为什么在spu中也要记录一份(聚合sku集合)?

  • 因为我们有时候需要把所有规格参数都查询出来,而不是只查询1个sku的属性。比如,商品详情页展示可选的规格参数时:

商品规格数据结构与商品表结构分析_第14张图片
刚好符号我们的结构,这样页面渲染就非常方便了。

2.2.3 SKU表

2.2.3.1 sku表结构

CREATE TABLE `tb_sku` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'sku id',
  `spu_id` bigint(20) NOT NULL COMMENT 'spu id',
  `title` varchar(255) NOT NULL COMMENT 'sku特有标题',
  `images` varchar(1000) DEFAULT '' COMMENT '商品的图片,多个图片以‘,’分割',
  `price` bigint(15) NOT NULL DEFAULT '0' COMMENT '销售价格,单位为分',
  `indexes` varchar(100) COMMENT '特有规格属性在spu属性模板中的对应下标组合',
  `own_spec` varchar(1000) COMMENT 'sku的特有规格参数,json格式',
  `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效,0无效,1有效',
  `create_time` datetime NOT NULL COMMENT '添加时间',
  `last_update_time` datetime NOT NULL COMMENT '最后修改时间',
  PRIMARY KEY (`id`),
  KEY `key_spu_id` (`spu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku表,该表表示具体的商品实体,如黑色的64GB的iphone 8';

还有一张stock表,代表库存;

因为库存字段写频率较高,而SKU的其它字段(颜色、价格)以读为主,因此我们将两张表分离,读写不会干扰(垂直拆分)。

2.2.3.2 stock库存表

CREATE TABLE `tb_stock` (
  `sku_id` bigint(20) NOT NULL COMMENT '库存对应的商品sku id',
  `seckill_stock` int(9) DEFAULT '0' COMMENT '可秒杀库存',
  `seckill_total` int(9) DEFAULT '0' COMMENT '秒杀总数量',
  `stock` int(9) NOT NULL COMMENT '库存数量',
  PRIMARY KEY (`sku_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存表,代表库存,秒杀库存等信息';

2.2.3.3 sku中的规格参数

2.2.3.3.1 indexes字段

在SPU表中,已经对特有规格参数及可选项进行了保存,结构如下:

{
    "4": [
        "香槟金",
        "樱花粉",
        "磨砂黑"
    ],
    "12": [
        "2GB",
        "3GB"
    ],
    "13": [
        "16GB",
        "32GB"
    ]
}

这些特有属性如果排列组合,会产生12个不同的SKU,而不同的SKU,其属性就是上面备选项中的一个。

比如:

  • 红米4X,香槟金,2GB内存,16GB存储
  • 红米4X,磨砂黑,2GB内存,32GB存储

你会发现,每一个属性值,对应于SPUoptions数组的一个选项,如果我们记录下角标,就是这样:

  • 红米4X,0,0,0
  • 红米4X,2,0,1

既然如此,我们就可以将不同角标串联起来,作为SPU下不同SKU的标示。这就是我们的indexes字段。
商品规格数据结构与商品表结构分析_第15张图片
这个设计在商品详情页(页面渲染)会特别有用:当用户点击选中一个特有属性,你就能根据 角标快速定位到sku。

2.2.3.3.2 own_spec字段

看结构:

{
	"4":"香槟金",
	"12":"2GB",
	"13":"16GB"
}

保存的是特有属性的键值对。

SPU中保存的是可选项,但不确定具体的值,而SKU中的保存的就是具体的值。

你可能感兴趣的:(乐优商城)