圍繞商品設計表
之前也寫過類似的數(shù)據(jù)庫設計方案,這一篇是為大家詳細講解參考京東商城圍繞商品怎么來設計數(shù)據(jù)庫,需要關注的細節(jié)很多,對字段進行詳解,結合功能實現(xiàn)分析每一個字段設計的意義
大家看完這篇文章后可以看看前面四篇文章電商項目數(shù)據(jù)庫設計方案,跟這一篇有點不同,之前是大多是參照蘇寧易購來設計的
我們在設計數(shù)據(jù)庫的時候,大多都是按照我們自己的實際需求來設計,提供這幾篇僅為大家參考學習,能夠舉一反三參與到項目實戰(zhàn)中,希望大家可以學到東西,同時,文章內容如果有錯誤的位置希望大家可以指正,共同學習。
接下來我們就言歸正傳,開始設計表
分類表?category
截取京東首頁,如下圖:
左側菜單欄,即顯示的商品分類,分類表我們應該設置哪些字段,我們可以參照京東商城思考下:
首先作為關系型MySQL數(shù)據(jù)庫,我們先定下通用字段,id、create_time、update_time這三個字段。
邏輯刪除字段看大家需求,我這里是自己做demo,就沒有設置邏輯刪除字段了,is_delete boolean類型,之前也寫過仿照蘇寧易購設計過數(shù)據(jù)庫,大家可以參考著看,僅供學習使用。
看上圖,我依次在菜單里面框出三個,在分類表中我們如何對菜單進行表示,字段名如何設置,很簡單,設置成level1、level2、level3三個字段分別表示就可以了,level1表示一級菜單,level2表示二級菜單,level3表示三級菜單。
但是想想,我們在實際業(yè)務中,如果我們開發(fā)一個商城以后有億級用戶,想添加其他的分類后,是不是要加level4、level5·····,這樣設計就有點不靈活了。
所以我們可以這樣設計,設計一個 parent_id 用來表示父類目id進行關聯(lián),頂級類目就是0,滿足可擴展性,而且字段也不冗余,符合三范式設計,什么是數(shù)據(jù)庫設計三范式, 不了解的同學可以看看這篇文章。
可以再設計一個 is_parentid 用來表示是否是父id,如果不是父id,肯定就是最后一次菜單,這里我不說是三級菜單,可能我們以后會進行擴展。
給一個 sort字段 進行權重分配,排序指數(shù),指數(shù)越小越靠前,這里就設計好了分類表。
品牌表?brand
設計數(shù)據(jù)表,我們依舊先列出通用字段,id、create_time、update_time
截取京東頁面:
從上圖我們可以看出,品牌設計也不怎么復雜,我們先看最上面,所有品牌,首字母表示,所有我們設計一個letter字段,用來表示品牌的首字母,可以用來做搜索。
繼續(xù)往下看,我們能看到什么?無非就是品牌的logo和名稱了吧,那就設計name字段表示名稱,image字段表示品牌的logo。還有沒有什么?
邏輯刪除也可以設置,這個放在關聯(lián)關系表來說!
品牌分類表?category_brand
前面我們已經(jīng)分析出了商品分類表和品牌表,它們之間有什么關系,我們這個階段來屢屢。
首先我們還是回到京東首頁,也就是我們在設計分類表的時候截取的京東那張圖片,對邊點擊一個三級分類,我這里點的手機,是不是看到的是品牌表這里的圖片,也就是說,一個分類下有多個品牌,如:(手機:有華為手機,蘋果手機,小米手機···)
接下來看一張圖:
華為品牌下也有很多分類,所以一個品牌下也有很多分類。
即分類表與品牌表是多對多的關系,多對多設計 中間表:
但是,你可能會發(fā)現(xiàn),這張表中并沒有設置外鍵約束,似乎與數(shù)據(jù)庫的設計范式不符。為什么這么做?
外鍵會嚴重影響數(shù)據(jù)庫的讀寫效率數(shù)據(jù)刪除時會比較麻煩
在電商行業(yè),性能是非常重要的。我們寧可在代碼中通過邏輯來維護表關系,也不設置外鍵。
如果使用邏輯刪除是否可以解決這個問題,大家可以思考下。
商品規(guī)格參數(shù)
商品規(guī)格參數(shù)相關的表是我們圍繞商品進行表設計所必不可少的,規(guī)格參數(shù)表應該如何設計 ?
通常情況下 一個商品有很多規(guī)格參數(shù),比如一個手機,有品牌、產(chǎn)品名稱、機身長度、機身重量、CPU、內存等等,把這些分別設計成字段,一張表也就幾十個字段,但是想想,這樣做會有什么不妥 ?
首先,我們設計數(shù)據(jù)庫是設計一個全品類的電商平臺,商品有很多種,我們打開京東看看,
手機的規(guī)格與包裝:
空調的規(guī)格與包裝:
還有很多很多,如果都設計到一張參數(shù)表,可想而知,是不合理的。
注意,我們發(fā)現(xiàn) 雖然商品不同、規(guī)格不同,但是同一個分類下的商品,比如都是手機,它們的規(guī)格參數(shù)名都是一樣的,只是值不一樣。所以,商品的規(guī)格參數(shù)應該 與 分類綁定,每一個分類都有統(tǒng)一的規(guī)格參數(shù)模板,不同商品的規(guī)格參數(shù)值是不同的。
因此:
規(guī)格參數(shù)的名稱(key)與值(value)應該分開保存一個分類 對應 一套規(guī)格參數(shù)模板,參數(shù)模板只有規(guī)格參數(shù)的名稱(key),沒有值(value)一個分類 對應 多個商品,每個商品的規(guī)格參數(shù)值都不同,所以每個商品都有自己的一套規(guī)格參數(shù)值
所以我們引入?yún)?shù)組與參數(shù)表:
規(guī)格參數(shù)的值我們暫且先不管,新增商品時再填寫規(guī)格參數(shù)值即可,我們先思考?規(guī)格參數(shù)模板(key)該怎么設計 ?
規(guī)格數(shù)據(jù)首先要分組,每個組再有不同的規(guī)格參數(shù)一個分類規(guī)格模板中,有多個規(guī)格組每個規(guī)格組中,包含多個規(guī)格參數(shù)
從面向對象的思想來看,我們的 規(guī)格組 和 規(guī)格參數(shù) 分別是兩類事物,并且組與組內參數(shù)成一對多關系,因此可以有兩個類分別描述它們,那么從數(shù)據(jù)庫設計來看,也就對應兩張表:
規(guī)格組表:tb_spec_group,一個商品分類下有多個規(guī)格組規(guī)格參數(shù)表:tb_spec_param,一個規(guī)格組下,有多個規(guī)格參數(shù)
如圖:
接下來要思考的就是:
描述規(guī)格組,需要哪些屬性?
因為 商品分類表 與 規(guī)格組表 是一對多的關系,一個商品分類下有多個規(guī)格組,所以 規(guī)格組表 里要有 商品分類Id 進行關聯(lián),規(guī)格組表字段可以設置為:
id:規(guī)格組自增Id
category_id:商品分類Id
name:組名
create_time:創(chuàng)建時間
update_time:更新時間
描述規(guī)格參數(shù),需要哪些屬性?
規(guī)格組表 與 規(guī)格參數(shù)表 也是一對多的關系,即一個組有多個參數(shù),所以需要關聯(lián)商品分類Id、規(guī)格組Id
想清楚上面的問題,就知道表該怎么設計了。
規(guī)格組表?spec_group
還是老套路:固定的三個字段 id、create_time、update_time。
name:是組名。
category_id:因為一個商品分類下有多個規(guī)格參數(shù)組,一對多的關系,所以設計 category_id 關聯(lián),實現(xiàn)一對多。
規(guī)格參數(shù)表?spec_param
先看表設計:
固定三個字段我們不需要過多的解釋,這是我們的套路:id、create_time、update_time。
category_id、group_id:一個商品分類有多個規(guī)格參數(shù)組,一個規(guī)格參數(shù)組有多個規(guī)格參數(shù)。
name:很好解釋,它是參數(shù)名。
接下來剩 numeric、unit、generic、searching、segments:
numeric:是否數(shù)值類型
上圖中,我們需要用兩個字段來描述:有的參數(shù)值是數(shù)字類型并且需要帶單位,有的不是數(shù)字類型。
所以我們設計 numeric字段 作為一個標識(標識是否是數(shù)值),如果是數(shù)值類型就必須伴隨著一個 unit字段 作為數(shù)字類型參數(shù)值的單位。
searching、segments 是用來做搜索用的,我們隨便打開一個頁面:
你會發(fā)現(xiàn),過濾條件中的屏幕尺寸、運行內存、網(wǎng)路、機身內存、電池容量、CPU核數(shù)等,在規(guī)格參數(shù)中都能找到:
也就是說,規(guī)格參數(shù)中的數(shù)據(jù),將來會有一部分作為搜索條件來使用。
我們可以在設計時,將這部分屬性標記出來,將來做搜索的時候,作為過濾條件。
與搜索相關的有兩個字段:
searching:標記是否用作過濾
true - 用于過濾搜索,false - 不用于過濾
segments:某些數(shù)值類型的參數(shù),如果在搜索時需要按區(qū)間劃分的,要在這里提前確定好劃分區(qū)間
比如電池容量,0-2000mAh,2000mAh-3000mAh,3000mAh-4000mAh
generic
一個全品類的電商網(wǎng)站 商品的種類繁多,每一件商品的屬性又有差別。為了更準確描述商品及細分差別,抽象出兩個概念:SPU和SKU,這里的generic屬性,代表是否是通用屬性,我們在商品數(shù)據(jù)結構時再聊,這里先了解一下。
了解SPU和SKU是什么
SPU:Standard Product Unit (標準產(chǎn)品單位) ,一組具有共同屬性的商品集。
SKU:Stock Keeping Unit(庫存量單位),在SPU商品集之下因具體特性不同而細分的每種商品。
以圖為例來看:
本頁的華為Mate10就是一個商品集?!? 華為Mate10?就是一個?SPU因為顏色、內存等規(guī)格的不同,在 “華為Mate10 商品集” 之下又細分出不同的 華為Mate10,比如:華為Mate10 亮黑色 128G版?!? 華為Mate10 亮黑色 128G版?就是一個?SKU
可以看出:
SPU是一個抽象的商品集概念,為了方便后臺的管理。SKU才是具體要銷售的商品,每一個SKU的價格、庫存都不一樣,用戶購買的是SKU 而不是SPU。
弄清楚了SPU和SKU的概念,接下來我們就著手開始設計商品表SPU和SKU了。
先看看京東頁面是怎么設計的,我們隨便打開一個商品:
看著這個圖片,我們自己來模擬設計下SPU表:
id:主鍵c_id:分類IDbrand_id:品牌IDname:商品名稱description:描述spec:規(guī)格after_service:售后服務comment:評價…
似乎并不復雜。
再看下SKU,大家覺得應該有什么字段?
id:主鍵spu_id:關聯(lián)的spuprice:價格images:圖片stock:庫存顏色?內存?硬盤?
SKU的特有規(guī)格也是變化的,不同商品,特有規(guī)格不一定相同,那么我們的表字段豈不是不確定 ?
SKU的特有規(guī)格應該怎么設計?
首先我們應該了解SKU的特有規(guī)格是什么,顧名思義,特有規(guī)格就是特有的,所有商品各自持有的,比如商品的內存,不同手機內存不一樣,有4G、6G、8G、16G…,顏色有紅色、綠色、黑色… 等等。
是不是SKU就是和商品分類有關系,在我這里,SKU特有規(guī)格 是和 商品規(guī)格參數(shù)有關系的,我們還是截取京東頁面來看看,如下圖:
顏色 —> 對應五種內存 —> 對應三種
這都是在參數(shù)規(guī)格中可以看到的,點擊哪一種,下面的參數(shù)就跟著變化。所以SKU的特有規(guī)格也是商品參數(shù)規(guī)格的一部分。
也就是說,我們沒必要單獨對SKU的特有規(guī)格進行設計,它可以看做是規(guī)格參數(shù)中的一部分。
這樣,規(guī)格參數(shù)中的屬性可以標記成兩部分:
SPU 下所有SKU共享的規(guī)格參數(shù)(稱為 通用規(guī)格)SPU?下每個SKU不同的規(guī)格參數(shù)(稱為 特有規(guī)格)
回想前面的伏筆,在設計的規(guī)格參數(shù)表時,有一個generic的字段 標記 “通用或特有規(guī)格”,就是為了這里使用。
這樣,商品SKU表就只需要設計規(guī)格屬性以外的其它字段了,商品SKU的規(guī)格參數(shù)由 之前設計好的 規(guī)格參數(shù)表 來保存,但?規(guī)格參數(shù)的值 依然是需要與商品相關聯(lián)。
接下來我們就來看看到底怎么設計:
SPU表? ?spu、spu_detail
tb_spu表與我們前面分析的基本類似,但是少了一些字段,比如商品描述等。
這里對SPU做了表的垂直拆分,把SPU的詳情放到了另一張表? tb_spu_detail:
這張表中的數(shù)據(jù)都比較大,為了不影響主表的查詢效率我們拆分出這張表。
需要注意的是這兩個字段:generic_spec 和 special_spec。
SKU表? ?sku
接下來對SPU表和SKU表字段進行下詳細的說明
我們先來看 tb_spu表,這個表應該沒有什么多大的問題,就是放一些共有的共有的字段,對cid說明一下吧,為什么設計了三個cid(分類id)字段,直接保存一個分類Id不就可以找到其他的分類Id了嗎 ? 這樣想是沒有問題的,我們主要是為了更好的頁面顯示才這樣設計的,大家也可以自行優(yōu)化。
然后 tb_spu表 控制商品的上下架、控制商品是否有效,比如一個SKU下的商品如果沒有庫存那么這個SKU就無效了,而一個SPU是包含多個SKU的,所以設計一個總的標志來標識某個SPU是否有效。
我們之所以把SPU表在分解出一個詳情表的原因就是考慮到性能的問題,把一些大字段單獨分出來,也就是垂直拆分,這樣可以提高數(shù)據(jù)檢索效率。
tb_spu_detail(商品詳情表) 我們主要講解兩個字段:
generic_spec:通用規(guī)格參數(shù)數(shù)據(jù)
special_spec:特有規(guī)格參數(shù)及可選值信息(json格式)
前面講過 規(guī)格參數(shù) 與 商品分類 綁定,同一分類的商品 會有一套相同的規(guī)格參數(shù) key(規(guī)格參數(shù)模板),但是這個分類下每個商品的規(guī)格參數(shù)值都不相同,因此要滿足下面幾點:
我們有一個規(guī)格參數(shù)表,跟分類關聯(lián),保存的就是某分類下的規(guī)格參數(shù)模板。我們還需要一個表,保存某個商品Id,以及和這個商品相關聯(lián)的規(guī)格參數(shù)的值(商品_規(guī)格參數(shù)值_中間表)。規(guī)格參數(shù)因為分成了通用規(guī)格參數(shù)和特有規(guī)格參數(shù),因此規(guī)格參數(shù)值也需要分別與 SPU和SKU關聯(lián):1. 通用的規(guī)格參數(shù)值與SPU關聯(lián)? ?2. 特有規(guī)格參數(shù)值與SKU關聯(lián)
但是我們并沒有增加新的表,來看下我們的表如何存儲這些信息。
generic_spec 字段:
如果要設計一張中間表A,來表示SPU中的通用規(guī)格屬性的值,至少需要下面的字段:
spu_id: 商品Idparam_id:規(guī)格參數(shù)Idparam_value: 規(guī)格參數(shù)的值
我們并沒有這么設計,而是把商品的規(guī)格參數(shù)值,直接保存到 tb_spu_detail (商品詳情表) 中,因此這些規(guī)格參數(shù)關聯(lián)的商品一目了然,那么上述中間表A 3個屬性中的 spu_id 就不需要了,剩下的就是 param_id(規(guī)格參數(shù)Id) 和 param_value(規(guī)格參數(shù)的值),兩者剛好是 一 一 對應關系,可以組成一個鍵值對,我們剛好可以用一個json結構來表示。
也就是用 tb_spu_detail表 中的 generic_spec 保存 通用規(guī)格參數(shù)的值,整體來看:
json結構,其中都是鍵值對:
key:對應 spec_param(規(guī)格參數(shù)表)的id,規(guī)格參數(shù)Idvalue:對應規(guī)格參數(shù)的值
special_spec 字段:
我們說SPU中只保存通用規(guī)格參數(shù),那么為什么又多出了一個special_spec字段呢?
以手機為例,品牌、操作系統(tǒng)等肯定都是通用規(guī)格參數(shù),而內存、顏色等肯定是特有的規(guī)格參數(shù)。
當你確定了一個SPU,比如小米的:紅米4X,因為顏色、內存等特有規(guī)格的不同,就會形成多個SKU。
如果把每個SKU的顏色、內存等特有規(guī)格都整理出來,就會形成下面的結果:
顏色:[白色,金色,玫瑰金]內存:[2G,3G]機身存儲:[16GB,32GB]
也就是說,把一個SPU下的每個SKU的特有規(guī)格參數(shù)值聚合到一起,就是special_spec字段。
來看數(shù)據(jù)格式:
也是json結構:
key:規(guī)格參數(shù)Idvalue:SPU特有規(guī)格數(shù)組
那么問題來了,為什么要在SPU中把所有SKU的規(guī)格參數(shù)聚合起來保存呢?
因為我們需要把商品的所有規(guī)格參數(shù)都查詢出來、展示給用戶進行選擇,而不是只查詢1個SKU的規(guī)格參數(shù)。
比如,商品詳情頁展示可選的規(guī)格參數(shù)時:
剛好符合我們的結構,這樣頁面渲染就非常方便了。
綜上所述,SPU與商品規(guī)格參數(shù)模板的關系如圖所示:
SPU表弄清楚了,在講解SKU表字段的時候就很容易理解了:
indexes: 特有規(guī)格參數(shù)在SPU參數(shù)模板中的對應下標組合。own_spec:SKU的特有規(guī)格參數(shù)鍵值對(json格式,反序列化時請使用linkedHashMap以保證有序)。enable: 是否有效。
SKU主要就是這3個字段,其他的字段大家看一眼就應該明白了。
own_spec 字段:
own_spec 描述的是SKU特有規(guī)格參數(shù)鍵值對(json格式),是一個商品具體的規(guī)格參數(shù),看數(shù)據(jù):
保存的是特有規(guī)格的鍵值對。
注意special_spec和own_spec兩個字段的配合:SPU中的special_spec保存的是“可選項”但不確定具體的值,而SKU中的own_spec保存的就是具體的值。
indexes 字段:
特有規(guī)格參數(shù)在SPU規(guī)格模板中的對應下標組合,保存到 indexes 字段。
在SPU表中,已經(jīng)對特有規(guī)格參數(shù)及可選項(special_spec字段)進行了保存,結構如下:
把上面的特有參數(shù)進行排列組合,就會有三種 :
Nova 5,白色,3GB,16GB :0_0_0? ? ?—>? 規(guī)格是:白色_3GB_16GBNova 5,金色,3GB,16GB :1_0_0? ? ?—>?規(guī)格是:金色_3GB_16GBNova 5,玫瑰金,3GB,16GB :2_0_0? ?—>?規(guī)格是:玫瑰金_3GB_16GB
如果在可選項中再添加其他的,排列組合的方式就會更多,這里通過每組可選項的下標進行記錄(如?0_0_0),這樣可以做到當用戶點擊哪一個可選項,我們就可以快速定位到SKU,我們把這種 “下標組合” 就記錄在 indexes 字段。
enable字段就是控制具體的一個商品的規(guī)格是否有效。
總結:
我們設計了哪幾張表,有什么關系
分類表: tb_category品牌表: tb_brand分類品牌表:tb_category_brand規(guī)格組表: tb_spec_group規(guī)格參數(shù)表:tb_spec_paramSPU表: tb_spuSPU詳情表: tb_spu_detailSKU表: tb_sku
關系:
一個分類有多個品牌,一個品牌屬于多個分類,所以是多對多一個分類有多個規(guī)格組,一個規(guī)格組有多個規(guī)格參數(shù),所以是一對多一個分類下有多個SPU,所以是一對多一個品牌下有多個SPU,所以是一對多一個SPU下有多個SKU,所以是一對多
The End ~
————————————————
版權聲明:本文為CSDN博主「一個不懂技術的人」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議。
原文鏈接: