一、前言
在很多应用场景中,通常需要给数据加上一些标识,以表明这条数据的某个特性,如:标识用户的性别、标识订单支付的渠道、标识商品的类型等等。在数据库设计时,通常我们会单独用一个字段来存储这些标识,如:可用gender字段来标识用户的性别,其值为“男”、“女”、“未知”这3种值中的一个;对于普通的具有有限固定的几个值的标识,这样自然没有什么问题,但是,对于一些同时具有多个属性且变化较大的就有些不合适了,比方说,标识智能手机的商品的类型时,其类型可标识为电子商品、娱乐商品、数码商品等多种类型,其具有的可分类属性众多且不固定;这些,就是本文需要讨论的:关于数据库设计时,给数据设计标识字段时的一些思考。
二、常见场景、问题与解决方法
场景一:
问题与分析:
用户是任何系统中最为重要的组成部分之一,在设计存储用户信息时,性别是用户信息的重要组成部分,应该如何存储呢?性别有 “男”、“女”2种情况,如果某个用户没有具体性别数据的话,可以标识为“未知”,因此,每一个用户,性别有“男”、“女”、“未知”共3种情况,我们需要在数据表字段中需要存储这3种情况的一种(实际应用可能需要更多情况以满足具体业务,这里姑且以常见的3种为例)。
思考与方法:
方法一:在用户信息表中,添加一个性别字段,其数据类型为char,其值为“未知”、“男”、“女”中的一个,当需要使用该值时(前端展示、分析统计等),直接取出使用即可。
方法二:在用户信息表中,添加一个字段,其数据类型为tinyint(一个字节),其值为 “0”、“1”、“2”,分别对应“未知”、“男”、“女”这3种情况,其中0对应的未知为默认值。当需要使用该值时,可针对不同的使用场景进行简单的转换,如前端需展示时可由数字转换成相应含义文字后再展示。
方法一的优点是语义明确、便于前端展示,不足之处有相对占用存储空间多、数据传输更耗流量等;方法二的优点是相对占用存储空间少、数据传输更省流量、一定程度上有利于数据统计分析,不足之处有展示时需要转换、数字语义需要约定等。笔者个人推荐使用方法二。(换个角度看,需要转换也带来了一定的灵活性,如:若某个业务需要展示性别为“保密”、“帅哥”、“靓女”,这样我们只需修改转换的地方即可,而不需修改数据库数据,这也有利于一个用户中心为不同的具体业务线提供服务)
场景二:
问题与分析:
电商平台通常会划分商品品类,如服饰类、食品类、数码类、书籍类等等,而有的商品可能具有多个商品品类属性,如智能手机,其既可划为数码类、又可划分为手机类、智能设备类,常见的场景是显示商品所属品类、修改商品的所属品类、查询某个品类下有哪些商品等,在这种情况下,该如何存储呢?
思考与方法:
假如平台的商品品类共有n种,那么,理论上某个商品的所属品类可能的组合就有[2^n-1]种情况,当然,实际上不会有这么多组合,但像用户选择兴趣爱好之类的场景可能的组合就多了,因此,上文场景一中的2种方法已不再适用。
可行的一个方法是:再引入一个品类关系表,用于存储商品品类与各商品的关系。这样的话,商品信息表本身用一个字符字段直接存储其所属品类信息,以满足基本需求,而操作某个品类下的商品的相关业务,则可通过品类关系表去做;一旦发生数据的变化,则同时维护这2个地方的数据。(事实上,通常的做法是,一件商品最多只能划分为有限的商品品类,一个人最多只能选择有限个兴趣爱好,如:一件商品最多只能所属3种品类,一个人最多只能选5个兴趣爱好)
场景三:
问题与分析:
在电商系统中,通常会通过各种优惠的方式来促销,如给用户发各种优惠券、积分抵扣等,用户提交订单时可以使用满足条件的各种优惠;那么,如何存储该订单具体使用了哪些优惠信息呢?
思考与方法:
与以上两种情况有所不同,以上的两种场景更多的业务场景是前端的展示与业务查询,而这种场景更多是标识优惠以计算用户实际所需支付金额,以及为后续业绩统计、制定促销计划、提高用户活跃度等提供数据依据。
这里我们举一个具体例子来逐步分析。
实例分析:
假设某平台为A平台,其平台当前可使用的优惠方式有以下几种: