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

    xiaoxiao2025-03-15  17

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

    1. 商品规格数据结构1.1 规格属性内容1.2 横表与数表1.3 表结构1.3.1 SpecGroup规格组1.3.2 SpecParam规格参数 1.4 从面向对象的角度分析 2. 商品表结构分析2.1 SPU和SKU2.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.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='规格参数的分组表,每个商品分类下有多个规格参数组';

    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='规格参数组下的参数名';

    通用属性

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

    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来标识自己。

    对组内属性进行描述 :上述的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商品集因具体特性不同而细分的每个商品

    以图为例:

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

    可以看出:

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

    2.2 表结构

    2.2.1 表结构分析

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

    所有sku共享的规格属性(称为通用属性),我们记录在spu表中每个sku不同的规格属性(称为特有属性),我们记录在sku表中

    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

    注:

    垂直拆分:表字段过多,实现数据的解耦水平拆分:表数据量多(一张表有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格式。 json结构,其中都是键值对:

    key:对应的规格参数的spec_param的idvalue:对应规格参数的值
    2.2.2.3.2 special_spec字段

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

    因此我们在SPU中,会把特有属性的所有值都记录下来,形成一个数组: 也是json结构:

    key:规格参数idvalue:spu属性的数组

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

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

    刚好符号我们的结构,这样页面渲染就非常方便了。

    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字段。 这个设计在商品详情页(页面渲染)会特别有用:当用户点击选中一个特有属性,你就能根据 角标快速定位到sku。

    2.2.3.3.2 own_spec字段

    看结构:

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

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

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

    最新回复(0)