关系型数据库中什么时候使用json字段

1,922 阅读4分钟

json和关系表是对不同关系的刻画。

json:

以营销活动和营销规则举例。
如果营销规则是营销活动的一个json字段,那么营销规则不是一个实体,它是营销活动的一个属性。再进一步说,如果我为五一节大促定制了满300-20的营销规则,规则便成为五一节大促的一个属性。和营销活动的名字是五一节大促一样,规则此时并不是一个独立的实体,它的存在依赖于五一节大促营销活动的存在。当国庆节大促这个营销活动上线的时候,我需要为国庆节大促活动再次描述一次这个活动的营销规则,即便仍然是满300-20相同的规则。

image.png

关系表:

如果营销活动是一个实体,营销规则也是一个实体。如果我为五一节大促定制了一个满300-20的营销规则,这个营销规则建立以后是一个实体。它和营销活动之间存在规则被活动使用的关系,但是它不是活动的一个属性,它的存在不依赖于五一节大促营销活动的存在。当国庆节大促这个营销活动上线的时候,我只需要为国庆节大促活动关联营销规则即可。这个时候要描述这两个实体的关系,需要使用一张关系表。并且由于一个营销规则可以存在于多个营销活动,一个营销活动也可以使用多个营销规则,是多对多的关系。是一张promotion_rule_rel关系表。

image.png

综合上述:json字段和关系表描述的是实体间不同的关系。如果希望规则可复用,那么可以使用关系表,但带来的代价是需要多维护一张表。相应的查询开销也会增加。

json和关系表各有优劣。

json:

同样以以营销活动和营销规则举例。json的优势在于数据结构灵活。如果五一节大促我的规则分别有满300-20【满减】,买够2件送1件【满赠】,全场8折【折扣】,简而言之,有很多种营销规则。此时如果我用数据库表来描述多变的规则,因为数据库表的字段是相对固定的,所以我们要描述多变的规则,要么出现大量冗余字段,要么出现字段的频繁变更。灵活性和拓展型比较差。反之,如果我用json。我只需要构造不同的值对象,就像

{
  "promotionType":"1", ## 满件赠
  "discountConfig": 
    {
      "goodsCount": 2,  ## 货物数量
      "giftCode": 76sjhsw ## 赠品标号
    }
}

{
  "promotionType":"2", ## 满减
  "discountConfig": 
    {
      "ladder": 300,  ## 阶梯
      "discount": 20 ## 优惠
    }
}

显而易见,灵活性和拓展型都更好。

但是json也有坏处。虽然可以通过数据库json函数获取到json字段中的key值,但是和表的字段相比,搜寻效率比较低。假想一个场景,营销活动中有个营销商品的json字段,就像


{"productList": [{"courseId": 463, "weekCount": 1}, {"courseId": 462, "weekCount": 48}]}

如果我想知道courseid=463的课程在哪些营销活动中出现过,这种拿json字段中的key值反向查询数据库记录的情况会出现比较复杂的sql。会加大查询的开销。 更进一步说,如果json中key值出现了读写频繁的外键或者信息,这个时候要慎重使用json字段。 并且如果从关系型数据库范式的角度出发,json字段本身应该是不符合数据库第一范式,实体中的某个属性还可以拆分成多个值。 如果我们决定要用json字段,我们考虑的条件应该是 1)数据查询流向是:数据库行->行的json字段。即获取到数据库某一条记录,根据这条记录去获取json中的信息。很少或者几乎没有反向查询路径,即行的json字段->数据库行。 2)需要json结构带来的灵活性

关系表:

关系表的优势在于数据库的一行中有关联的所有entity间的键关系。查询效率很好,双向查询都很方便。 关系表的劣势是维护的表多了一张,如果所有关系都用关系表链接,一定会出现很多join操作。长远来看,一是表数量的膨胀增加维护成本且不利于系统的稳定性,二是join操作耗费性能。 但是又如果你的系统如果构建的域比较好,订单域,商品域有控制,并且从服务模块的粒度控制了数据库,表数量的膨胀并不是一个问题。